(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / tools / SqlSharp / SqlSharpCli.cs
blob6ad5aa61699934b1f5f37e5247f526de91f58e54
1 //
2 // SqlSharpCli.cs - main driver for Mono SQL Query Command Line Interface
3 // found in mcs/tools/SqlSharp
4 //
5 // This program is included in Mono and is licenced under the GPL.
6 // http://www.fsf.org/licenses/gpl.html
7 //
8 // For more information about Mono,
9 // visit http://www.mono-project.com/
11 // To build SqlSharpCli.cs
12 // $ mcs SqlSharpCli.cs /r:System.Data.dll
14 // To run with mono:
15 // $ mono SqlSharpCli.exe
17 // To run with mint:
18 // $ mint SqlSharpCli.exe
20 // To run batch commands and get the output, do something like:
21 // $ cat commands.txt | mono SqlSharpCli.exe > results.txt
23 // Author:
24 // Daniel Morgan <danielmorgan@verizon.net>
26 // (C)Copyright 2002-2004 Daniel Morgan
29 using System;
30 using System.Collections;
31 using System.Data;
32 using System.Data.Common;
33 using System.Data.OleDb;
34 using System.Data.SqlClient;
35 using System.IO;
36 using System.Reflection;
37 using System.Runtime.Remoting;
38 using System.Text;
40 namespace Mono.Data.SqlSharp {
42 public enum FileFormat {
43 Html,
44 Xml,
45 CommaSeparatedValues,
46 TabSeparated,
47 Normal
50 // SQL Sharp - Command Line Interface
51 public class SqlSharpCli {
53 // provider supports
54 private bool UseParameters = true;
55 private bool UseSimpleReader = false;
57 private IDbConnection conn = null;
59 private string provider = ""; // name of internal provider
60 // {OleDb,SqlClient,MySql,Odbc,Oracle,
61 // PostgreSql,SqlLite,Sybase,Tds} however, it
62 // can be set to LOADEXTPROVIDER to load an external provider
63 private string providerAssembly = "";
64 // filename of assembly
65 // for example: "Mono.Data.MySql"
66 private string providerConnectionClass = "";
67 // Connection class
68 // in the provider assembly that implements the IDbConnection
69 // interface. for example: "Mono.Data.MySql.MySqlConnection"
70 Type conType;
71 private StringBuilder build = null; // SQL string to build
72 private string buff = ""; // SQL string buffer
74 private string connectionString = "";
76 private string inputFilename = "";
77 private string outputFilename = "";
78 private StreamReader inputFilestream = null;
79 private StreamWriter outputFilestream = null;
81 private FileFormat outputFileFormat = FileFormat.Html;
83 private bool silent = false;
84 private bool showHeader = true;
86 private Hashtable internalVariables = new Hashtable();
88 // DisplayResult - used to Read() display a result set
89 // called by DisplayData()
90 public void DisplayResult(IDataReader reader, DataTable schemaTable) {
92 const string zero = "0";
93 StringBuilder column = null;
94 StringBuilder line = null;
95 StringBuilder hdrUnderline = null;
96 string outData = "";
97 int hdrLen = 0;
99 int spacing = 0;
100 int columnSize = 0;
101 int c;
103 char spacingChar = ' '; // a space
104 char underlineChar = '='; // an equal sign
106 string dataType; // .NET Type
107 Type theType;
108 //string dataTypeName; // native Database type
109 DataRow row; // schema row
111 line = new StringBuilder();
112 hdrUnderline = new StringBuilder();
114 OutputLine("Fields in Query Result: " +
115 reader.FieldCount);
116 OutputLine("");
118 for(c = 0; c < schemaTable.Rows.Count; c++) {
120 DataRow schemaRow = schemaTable.Rows[c];
121 string columnHeader = (string) schemaRow["ColumnName"];
122 if(columnHeader.Equals(""))
123 columnHeader = "?column?";
124 if(columnHeader.Length > 32)
125 columnHeader = columnHeader.Substring(0,32);
127 // spacing
128 columnSize = (int) schemaRow["ColumnSize"];
129 theType = (Type) schemaRow["DataType"];
130 dataType = theType.ToString();
132 switch(dataType) {
133 case "System.DateTime":
134 columnSize = 19;
135 break;
136 case "System.Boolean":
137 columnSize = 5;
138 break;
141 hdrLen = (columnHeader.Length > columnSize) ?
142 columnHeader.Length : columnSize;
144 if(hdrLen < 0)
145 hdrLen = 0;
146 if(hdrLen > 32)
147 hdrLen = 32;
149 line.Append(columnHeader);
150 if(columnHeader.Length < hdrLen) {
151 spacing = hdrLen - columnHeader.Length;
152 line.Append(spacingChar, spacing);
154 hdrUnderline.Append(underlineChar, hdrLen);
156 line.Append(" ");
157 hdrUnderline.Append(" ");
159 OutputHeader(line.ToString());
160 line = null;
162 OutputHeader(hdrUnderline.ToString());
163 OutputHeader("");
164 hdrUnderline = null;
166 int rows = 0;
168 // column data
169 while(reader.Read()) {
170 rows++;
172 line = new StringBuilder();
173 for(c = 0; c < reader.FieldCount; c++) {
174 int dataLen = 0;
175 string dataValue = "";
176 column = new StringBuilder();
177 outData = "";
179 row = schemaTable.Rows[c];
180 string colhdr = (string) row["ColumnName"];
181 if(colhdr.Equals(""))
182 colhdr = "?column?";
183 if(colhdr.Length > 32)
184 colhdr = colhdr.Substring(0, 32);
186 columnSize = (int) row["ColumnSize"];
187 theType = (Type) row["DataType"];
188 dataType = theType.ToString();
190 switch(dataType) {
191 case "System.DateTime":
192 columnSize = 19;
193 break;
194 case "System.Boolean":
195 columnSize = 5;
196 break;
199 columnSize = (colhdr.Length > columnSize) ?
200 colhdr.Length : columnSize;
202 if(columnSize < 0)
203 columnSize = 0;
204 if(columnSize > 32)
205 columnSize = 32;
207 dataValue = "";
209 if(reader.IsDBNull(c)) {
210 dataValue = "";
211 dataLen = 0;
213 else {
214 StringBuilder sb;
215 DateTime dt;
216 if(dataType.Equals("System.DateTime")) {
217 // display date in ISO format
218 // "YYYY-MM-DD HH:MM:SS"
219 dt = reader.GetDateTime(c);
220 sb = new StringBuilder();
221 // year
222 if(dt.Year < 10)
223 sb.Append("000" + dt.Year);
224 else if(dt.Year < 100)
225 sb.Append("00" + dt.Year);
226 else if(dt.Year < 1000)
227 sb.Append("0" + dt.Year);
228 else
229 sb.Append(dt.Year);
230 sb.Append("-");
231 // month
232 if(dt.Month < 10)
233 sb.Append(zero + dt.Month);
234 else
235 sb.Append(dt.Month);
236 sb.Append("-");
237 // day
238 if(dt.Day < 10)
239 sb.Append(zero + dt.Day);
240 else
241 sb.Append(dt.Day);
242 sb.Append(" ");
243 // hour
244 if(dt.Hour < 10)
245 sb.Append(zero + dt.Hour);
246 else
247 sb.Append(dt.Hour);
248 sb.Append(":");
249 // minute
250 if(dt.Minute < 10)
251 sb.Append(zero + dt.Minute);
252 else
253 sb.Append(dt.Minute);
254 sb.Append(":");
255 // second
256 if(dt.Second < 10)
257 sb.Append(zero + dt.Second);
258 else
259 sb.Append(dt.Second);
261 dataValue = sb.ToString();
263 else {
264 dataValue = reader.GetValue(c).ToString();
267 dataLen = dataValue.Length;
268 if(dataLen < 0) {
269 dataValue = "";
270 dataLen = 0;
272 if(dataLen > 32) {
273 dataValue = dataValue.Substring(0,32);
274 dataLen = 32;
277 columnSize = columnSize > dataLen ? columnSize : dataLen;
279 // spacing
280 spacingChar = ' ';
281 if(columnSize < colhdr.Length) {
282 spacing = colhdr.Length - columnSize;
283 column.Append(spacingChar, spacing);
285 if(dataLen < columnSize) {
286 spacing = columnSize - dataLen;
287 column.Append(spacingChar, spacing);
288 switch(dataType) {
289 case "System.Int16":
290 case "System.Int32":
291 case "System.Int64":
292 case "System.Single":
293 case "System.Double":
294 case "System.Decimal":
295 outData = column.ToString() + dataValue;
296 break;
297 default:
298 outData = dataValue + column.ToString();
299 break;
302 else
303 outData = dataValue;
305 line.Append(outData);
306 line.Append(" ");
308 OutputData(line.ToString());
309 line = null;
311 OutputLine("\nRows retrieved: " + rows.ToString());
314 public void OutputDataToHtmlFile(IDataReader rdr, DataTable dt) {
316 StringBuilder strHtml = new StringBuilder();
318 strHtml.Append("<html> \n <head> <title>");
319 strHtml.Append("Results");
320 strHtml.Append("</title> </head>");
321 strHtml.Append("<body>");
322 strHtml.Append("<h1> Results </h1>");
323 strHtml.Append("<table border=1>");
325 outputFilestream.WriteLine(strHtml.ToString());
327 strHtml = null;
328 strHtml = new StringBuilder();
330 strHtml.Append("<tr>");
331 foreach (DataRow schemaRow in dt.Rows) {
332 strHtml.Append("<td> <b>");
333 object dataObj = schemaRow["ColumnName"];
334 string sColumnName = dataObj.ToString();
335 strHtml.Append(sColumnName);
336 strHtml.Append("</b> </td>");
338 strHtml.Append("</tr>");
339 outputFilestream.WriteLine(strHtml.ToString());
340 strHtml = null;
342 int col = 0;
343 string dataValue = "";
345 while(rdr.Read()) {
346 strHtml = new StringBuilder();
348 strHtml.Append("<tr>");
349 for(col = 0; col < rdr.FieldCount; col++) {
351 // column data
352 if(rdr.IsDBNull(col) == true)
353 dataValue = "NULL";
354 else {
355 object obj = rdr.GetValue(col);
356 dataValue = obj.ToString();
358 strHtml.Append("<td>");
359 strHtml.Append(dataValue);
360 strHtml.Append("</td>");
362 strHtml.Append("\t\t</tr>");
363 outputFilestream.WriteLine(strHtml.ToString());
364 strHtml = null;
366 outputFilestream.WriteLine(" </table> </body> \n </html>");
367 strHtml = null;
370 // DisplayData - used to display any Result Sets
371 // from execution of SQL SELECT Query or Queries
372 // called by DisplayData.
373 // ExecuteSql() only calls this function
374 // for a Query, it does not get
375 // for a Command.
376 public void DisplayData(IDataReader reader) {
378 DataTable schemaTable = null;
379 int ResultSet = 0;
381 OutputLine("Display any result sets...");
383 do {
384 // by Default, SqlDataReader has the
385 // first Result set if any
387 ResultSet++;
388 OutputLine("Display the result set " + ResultSet);
390 schemaTable = reader.GetSchemaTable();
392 if(reader.FieldCount > 0) {
393 // SQL Query (SELECT)
394 // RecordsAffected -1 and DataTable has a reference
395 OutputQueryResult(reader, schemaTable);
397 else if(reader.RecordsAffected >= 0) {
398 // SQL Command (INSERT, UPDATE, or DELETE)
399 // RecordsAffected >= 0
400 Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
402 else {
403 // SQL Command (not INSERT, UPDATE, nor DELETE)
404 // RecordsAffected -1 and DataTable has a null reference
405 Console.WriteLine("SQL Command Executed.");
408 // get next result set (if anymore is left)
409 } while(reader.NextResult());
412 // display the result in a simple way
413 // new ADO.NET providers may have not certain
414 // things implemented yet, such as, TableSchema
415 // support
416 public void DisplayDataSimple(IDataReader reader) {
418 int row = 0;
419 Console.WriteLine("Reading Data using simple reader...");
420 while(reader.Read()){
421 row++;
422 Console.WriteLine("Row: " + row);
423 for(int col = 0; col < reader.FieldCount; col++) {
424 int co = col + 1;
425 Console.WriteLine(" Field: " + co);
427 string dname = (string) reader.GetName(col);
428 if(dname == null)
429 dname = "?column?";
430 if(dname.Equals(String.Empty))
431 dname = "?column?";
432 Console.WriteLine(" Name: " + dname);
434 string dvalue = "";
435 if (reader.IsDBNull(col))
436 dvalue = "(null)";
437 else
438 dvalue = reader.GetValue(col).ToString();
439 Console.WriteLine(" Value: " + dvalue);
442 Console.WriteLine("\n" + row + " ROWS RETRIEVED\n");
445 public void OutputQueryResult(IDataReader dreader, DataTable dtable) {
446 if(outputFilestream == null) {
447 DisplayResult(dreader, dtable);
449 else {
450 switch(outputFileFormat) {
451 case FileFormat.Normal:
452 DisplayResult(dreader, dtable);
453 break;
454 case FileFormat.Html:
455 OutputDataToHtmlFile(dreader, dtable);
456 break;
457 default:
458 Console.WriteLine("Error: Output data file format not supported.");
459 break;
464 public void BuildParameters(IDbCommand cmd) {
465 if(UseParameters == true) {
467 ParametersBuilder parmsBuilder =
468 new ParametersBuilder(cmd,
469 BindVariableCharacter.Colon);
471 Console.WriteLine("Get Parameters (if any)...");
472 parmsBuilder.ParseParameters();
473 IList parms = (IList) cmd.Parameters;
475 Console.WriteLine("Print each parm...");
476 for(int p = 0; p < parms.Count; p++) {
477 string theParmName;
479 IDataParameter prm = (IDataParameter) parms[p];
480 theParmName = prm.ParameterName;
482 string inValue = "";
483 bool found;
484 if(parmsBuilder.ParameterMarkerCharacter == '?') {
485 Console.Write("Enter Parameter " +
486 (p + 1).ToString() +
487 ": ");
488 inValue = Console.ReadLine();
489 prm.Value = inValue;
491 else {
492 found = GetInternalVariable(theParmName, out inValue);
493 if(found == true) {
494 prm.Value = inValue;
496 else {
497 Console.Write("Enter Parameter " + (p + 1).ToString() +
498 ": " + theParmName + ": ");
499 inValue = Console.ReadLine();
500 prm.Value = inValue;
504 parmsBuilder = null;
508 // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
509 public void ExecuteSql(string sql) {
510 string msg = "";
512 Console.WriteLine("Execute SQL: " + sql);
514 IDbCommand cmd = null;
515 IDataReader reader = null;
517 cmd = conn.CreateCommand();
519 // set command properties
520 cmd.CommandType = CommandType.Text;
521 cmd.CommandText = sql;
522 cmd.Connection = conn;
524 BuildParameters(cmd);
526 try {
527 reader = cmd.ExecuteReader();
529 if(UseSimpleReader == false)
530 DisplayData(reader);
531 else
532 DisplayDataSimple(reader);
534 reader.Close();
535 reader = null;
537 catch(Exception e) {
538 msg = "Error: " + e;
539 // msg = "Error: " + e.Message;
540 Console.WriteLine(msg);
541 //if(reader != null) {
542 // if(reader.IsClosed == false)
543 // reader.Close();
544 reader = null;
547 finally {
548 // cmd.Dispose();
549 cmd = null;
553 // ExecuteSql - Execute the SQL Commands (no SELECTs)
554 public void ExecuteSqlNonQuery(string sql) {
555 string msg = "";
557 Console.WriteLine("Execute SQL Non Query: " + sql);
559 IDbCommand cmd = null;
560 int rowsAffected = -1;
562 cmd = conn.CreateCommand();
564 // set command properties
565 cmd.CommandType = CommandType.Text;
566 cmd.CommandText = sql;
567 cmd.Connection = conn;
569 BuildParameters(cmd);
571 try {
572 rowsAffected = cmd.ExecuteNonQuery();
573 cmd = null;
574 Console.WriteLine("Rows affected: " + rowsAffected);
576 catch(Exception e) {
577 msg = "Error: " + e.Message;
578 Console.WriteLine(msg);
580 finally {
581 // cmd.Dispose();
582 cmd = null;
586 public void ExecuteSqlScalar(string sql) {
587 string msg = "";
589 Console.WriteLine("Execute SQL Scalar: " + sql);
591 IDbCommand cmd = null;
592 string retrievedValue = "";
594 cmd = conn.CreateCommand();
596 // set command properties
597 cmd.CommandType = CommandType.Text;
598 cmd.CommandText = sql;
599 cmd.Connection = conn;
601 BuildParameters(cmd);
603 try {
604 retrievedValue = (string) cmd.ExecuteScalar().ToString();
605 Console.WriteLine("Retrieved value: " + retrievedValue);
607 catch(Exception e) {
608 msg = "Error: " + e.Message;
609 Console.WriteLine(msg);
611 finally {
612 // cmd.Dispose();
613 cmd = null;
617 public void ExecuteSqlXml(string sql, string[] parms) {
618 string filename = "";
620 if(parms.Length != 2) {
621 Console.WriteLine("Error: wrong number of parameters");
622 return;
624 try {
625 filename = parms[1];
627 catch(Exception e) {
628 Console.WriteLine("Error: Unable to setup output results file. " +
629 e.Message);
630 return;
633 try {
634 Console.WriteLine("Execute SQL XML: " + sql);
636 IDbCommand cmd = null;
638 cmd = conn.CreateCommand();
640 // set command properties
641 cmd.CommandType = CommandType.Text;
642 cmd.CommandText = sql;
643 cmd.Connection = conn;
645 BuildParameters(cmd);
647 Console.WriteLine("Creating new DataSet...");
648 DataSet dataSet = new DataSet ();
650 Console.WriteLine("Creating new provider DataAdapter...");
651 DbDataAdapter adapter = CreateNewDataAdapter (cmd, conn);
653 Console.WriteLine("Filling DataSet via Data Adapter...");
654 adapter.Fill (dataSet);
656 Console.WriteLine ("Write DataSet to XML file: " +
657 filename);
658 dataSet.WriteXml (filename);
660 Console.WriteLine ("Done.");
662 catch(Exception exexml) {
663 Console.WriteLine("Error: Execute SQL XML Failure: " +
664 exexml);
668 public DbDataAdapter CreateNewDataAdapter (IDbCommand command,
669 IDbConnection connection) {
671 DbDataAdapter adapter = null;
673 switch(provider) {
674 case "OLEDB":
675 adapter = (DbDataAdapter) new OleDbDataAdapter ();
676 break;
677 case "SQLCLIENT":
678 adapter = (DbDataAdapter) new SqlDataAdapter ();
679 break;
680 case "LOADEXTPROVIDER":
681 adapter = CreateExternalDataAdapter (command, connection);
682 if (adapter == null)
683 return null;
684 break;
685 default:
686 Console.WriteLine("Error: Data Adapter not found in provider.");
687 return null;
689 IDbDataAdapter dbAdapter = (IDbDataAdapter) adapter;
690 dbAdapter.SelectCommand = command;
692 return adapter;
695 public DbDataAdapter CreateExternalDataAdapter (IDbCommand command,
696 IDbConnection connection) {
698 DbDataAdapter adapter = null;
700 Assembly ass = Assembly.Load (providerAssembly);
701 Type [] types = ass.GetTypes ();
702 foreach (Type t in types) {
703 if (t.IsSubclassOf (typeof(System.Data.Common.DbDataAdapter))) {
704 if(t.Namespace.Equals(conType.Namespace))
705 adapter = (DbDataAdapter) Activator.CreateInstance (t);
709 return adapter;
712 // like ShowHelp - but only show at the beginning
713 // only the most important commands are shown
714 // like help and quit
715 public void StartupHelp() {
716 Console.WriteLine(@"Type: \Q to quit");
717 Console.WriteLine(@" \ConnectionString to set the ConnectionString");
718 Console.WriteLine(@" \Provider to set the Provider:");
719 Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,DB2,");
720 Console.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds)");
721 Console.WriteLine(@" \Open to open the connection");
722 Console.WriteLine(@" \Close to close the connection");
723 Console.WriteLine(@" \e to execute SQL query (SELECT)");
724 Console.WriteLine(@" \h to show help (all commands).");
725 Console.WriteLine(@" \defaults to show default variables.");
726 Console.WriteLine();
729 // ShowHelp - show the help - command a user can enter
730 public void ShowHelp() {
731 Console.WriteLine("");
732 Console.WriteLine(@"Type: \Q to quit");
733 Console.WriteLine(@" \ConnectionString to set the ConnectionString");
734 Console.WriteLine(@" \Provider to set the Provider:");
735 Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,MSODBC,");
736 Console.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds}");
737 Console.WriteLine(@" \Open to open the connection");
738 Console.WriteLine(@" \Close to close the connection");
739 Console.WriteLine(@" \e to execute SQL query (SELECT)");
740 Console.WriteLine(@" \exenonquery to execute an SQL non query (not a SELECT).");
741 Console.WriteLine(@" \exescalar to execute SQL to get a single row and single column.");
742 Console.WriteLine(@" \exexml FILENAME to execute SQL and save output to XML file.");
743 Console.WriteLine(@" \f FILENAME to read a batch of SQL# commands from file.");
744 Console.WriteLine(@" \o FILENAME to write result of commands executed to file.");
745 Console.WriteLine(@" \load FILENAME to load from file SQL commands into SQL buffer.");
746 Console.WriteLine(@" \save FILENAME to save SQL commands from SQL buffer to file.");
747 Console.WriteLine(@" \h to show help (all commands).");
748 Console.WriteLine(@" \defaults to show default variables, such as,");
749 Console.WriteLine(@" Provider and ConnectionString.");
750 Console.WriteLine(@" \s {TRUE, FALSE} to silent messages.");
751 Console.WriteLine(@" \r to reset or clear the query buffer.");
752 WaitForEnterKey();
753 Console.WriteLine(@" \set NAME VALUE to set an internal variable.");
754 Console.WriteLine(@" \unset NAME to remove an internal variable.");
755 Console.WriteLine(@" \variable NAME to display the value of an internal variable.");
756 Console.WriteLine(@" \loadextprovider ASSEMBLY CLASS to load the provider");
757 Console.WriteLine(@" use the complete name of its assembly and");
758 Console.WriteLine(@" its Connection class.");
759 Console.WriteLine(@" \print - show what's in the SQL buffer now.");
760 Console.WriteLine(@" \UseParameters (TRUE,FALSE) to use parameters when executing SQL.");
761 Console.WriteLine(@" \UseSimpleReader (TRUE,FALSE) to use simple reader when displaying results.");
762 Console.WriteLine();
765 public bool WaitForEnterKey() {
766 Console.Write("Waiting... Press Enter key to continue. ");
767 string entry = Console.ReadLine();
768 if (entry.ToUpper() == "Q")
769 return false;
770 return true;
773 // ShowDefaults - show defaults for connection variables
774 public void ShowDefaults() {
775 Console.WriteLine();
776 if(provider.Equals(""))
777 Console.WriteLine("Provider is not set.");
778 else {
779 Console.WriteLine("The default Provider is " + provider);
780 if(provider.Equals("LOADEXTPROVIDER")) {
781 Console.WriteLine(" Assembly: " +
782 providerAssembly);
783 Console.WriteLine(" Connection Class: " +
784 providerConnectionClass);
787 Console.WriteLine();
788 if(connectionString.Equals(""))
789 Console.WriteLine("ConnectionString is not set.");
790 else {
791 Console.WriteLine("The default ConnectionString is: ");
792 Console.WriteLine(" \"" + connectionString + "\"");
793 Console.WriteLine();
797 // OpenDataSource - open connection to the data source
798 public void OpenDataSource() {
799 string msg = "";
801 Console.WriteLine("Attempt to open connection...");
803 try {
804 switch(provider) {
805 case "OLEDB":
806 conn = new OleDbConnection();
807 break;
808 case "SQLCLIENT":
809 conn = new SqlConnection();
810 break;
811 case "LOADEXTPROVIDER":
812 if(LoadExternalProvider() == false)
813 return;
814 break;
815 default:
816 Console.WriteLine("Error: Bad argument or provider not supported.");
817 return;
820 catch(Exception e) {
821 msg = "Error: Unable to create Connection object because: " +
822 e.Message;
823 Console.WriteLine(msg);
824 return;
827 conn.ConnectionString = connectionString;
829 try {
830 conn.Open();
831 if(conn.State == ConnectionState.Open)
832 Console.WriteLine("Open was successfull.");
834 catch(Exception e) {
835 msg = "Exception Caught Opening. " + e.Message;
836 Console.WriteLine(msg);
837 conn = null;
841 // CloseDataSource - close the connection to the data source
842 public void CloseDataSource() {
843 string msg = "";
845 if(conn != null) {
846 Console.WriteLine("Attempt to Close...");
847 try {
848 conn.Close();
849 Console.WriteLine("Close was successfull.");
851 catch(Exception e) {
852 msg = "Exeception Caught Closing. " + e.Message;
853 Console.WriteLine(msg);
855 conn = null;
859 // ChangeProvider - change the provider string variable
860 public void ChangeProvider(string[] parms) {
862 string[] extp;
864 if(parms.Length == 2) {
865 string parm = parms[1].ToUpper();
866 switch(parm) {
867 case "ORACLE":
868 extp = new string[3] {
869 "\\loadextprovider",
870 @"System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
871 "System.Data.OracleClient.OracleConnection"};
872 SetupExternalProvider(extp);
873 UseParameters = false;
874 UseSimpleReader = false;
875 break;
876 case "TDS":
877 extp = new string[3] {
878 "\\loadextprovider",
879 @"Mono.Data.TdsClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
880 "Mono.Data.TdsClient.TdsConnection"};
881 SetupExternalProvider(extp);
882 UseParameters = false;
883 UseSimpleReader = false;
884 break;
885 case "SYBASE":
886 extp = new string[3] {
887 "\\loadextprovider",
888 @"Mono.Data.SybaseClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
889 "Mono.Data.SybaseClient.SybaseConnection"};
890 SetupExternalProvider(extp);
891 UseParameters = false;
892 UseSimpleReader = false;
893 break;
894 case "MYSQL":
895 case "MYSQLNET":
896 extp = new string[3] {
897 "\\loadextprovider",
898 @"ByteFX.Data, Version=0.7.6.1, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
899 "ByteFX.Data.MySqlClient.MySqlConnection"};
900 SetupExternalProvider(extp);
901 UseParameters = false;
902 UseSimpleReader = false;
903 break;
904 case "SQLITE":
905 extp = new string[3] {
906 "\\loadextprovider",
907 @"Mono.Data.SqliteClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
908 "Mono.Data.SqliteClient.SqliteConnection"};
909 SetupExternalProvider(extp);
910 UseParameters = false;
911 UseSimpleReader = true;
912 break;
913 case "SQLCLIENT":
914 UseParameters = false;
915 UseSimpleReader = false;
916 provider = parm;
917 break;
918 case "ODBC": // for MS NET 1.1 and above
919 extp = new string[3] {
920 "\\loadextprovider",
921 @"System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
922 "System.Data.Odbc.OdbcConnection"};
923 SetupExternalProvider(extp);
924 UseParameters = false;
925 UseSimpleReader = false;
926 break;
927 case "MSODBC": // for MS NET 1.0
928 extp = new string[3] {
929 "\\loadextprovider",
930 @"Microsoft.Data.Odbc, Culture=neutral, PublicKeyToken=b77a5c561934e089, Version=1.0.3300.0",
931 "Microsoft.Data.Odbc.OdbcConnection"};
932 SetupExternalProvider(extp);
933 UseParameters = false;
934 UseSimpleReader = false;
935 break;
936 case "OLEDB":
937 UseParameters = false;
938 UseSimpleReader = true;
939 provider = parm;
940 break;
941 case "FIREBIRD":
942 extp = new string[3] {
943 "\\loadextprovider",
944 @"FirebirdSql.Data.Firebird, Version=1.6.3.0, Culture=neutral, PublicKeyToken=e1b4f92304d7b12f",
945 "FirebirdSql.Data.Firebird.FbConnection"};
946 SetupExternalProvider(extp);
947 UseParameters = false;
948 UseSimpleReader = false;
949 break;
950 case "POSTGRESQL":
951 case "NPGSQL":
952 extp = new string[3] {
953 "\\loadextprovider",
954 @"Npgsql, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7",
955 "Npgsql.NpgsqlConnection"};
956 SetupExternalProvider(extp);
957 UseParameters = false;
958 UseSimpleReader = false;
959 break;
960 default:
961 Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
962 break;
964 Console.WriteLine("The default Provider is " + provider);
965 if(provider.Equals("LOADEXTPROVIDER")) {
966 Console.WriteLine(" Assembly: " +
967 providerAssembly);
968 Console.WriteLine(" Connection Class: " +
969 providerConnectionClass);
972 else
973 Console.WriteLine("Error: provider only has one parameter.");
976 // ChangeConnectionString - change the connection string variable
977 public void ChangeConnectionString(string entry) {
979 if(entry.Length > 18)
980 connectionString = entry.Substring(18, entry.Length - 18);
981 else
982 connectionString = "";
985 public void SetupOutputResultsFile(string[] parms) {
986 if(parms.Length != 2) {
987 Console.WriteLine("Error: wrong number of parameters");
988 return;
990 try {
991 outputFilestream = new StreamWriter(parms[1]);
993 catch(Exception e) {
994 Console.WriteLine("Error: Unable to setup output results file. " +
995 e.Message);
996 return;
1000 public void SetupInputCommandsFile(string[] parms) {
1001 if(parms.Length != 2) {
1002 Console.WriteLine("Error: wrong number of parameters");
1003 return;
1005 try {
1006 inputFilestream = new StreamReader(parms[1]);
1008 catch(Exception e) {
1009 Console.WriteLine("Error: Unable to setup input commmands file. " +
1010 e.Message);
1011 return;
1015 public void LoadBufferFromFile(string[] parms) {
1016 if(parms.Length != 2) {
1017 Console.WriteLine("Error: wrong number of parameters");
1018 return;
1020 string inFilename = parms[1];
1021 try {
1022 StreamReader sr = new StreamReader( inFilename);
1023 StringBuilder buffer = new StringBuilder();
1024 string NextLine;
1026 while((NextLine = sr.ReadLine()) != null) {
1027 buffer.Append(NextLine);
1028 buffer.Append("\n");
1030 sr.Close();
1031 buff = buffer.ToString();
1032 build = null;
1033 build = new StringBuilder();
1034 build.Append(buff);
1036 catch(Exception e) {
1037 Console.WriteLine("Error: Unable to read file into SQL Buffer. " +
1038 e.Message);
1042 public void SaveBufferToFile(string[] parms) {
1043 if(parms.Length != 2) {
1044 Console.WriteLine("Error: wrong number of parameters");
1045 return;
1047 string outFilename = parms[1];
1048 try {
1049 StreamWriter sw = new StreamWriter(outFilename);
1050 sw.WriteLine(buff);
1051 sw.Close();
1053 catch(Exception e) {
1054 Console.WriteLine("Error: Could not save SQL Buffer to file." +
1055 e.Message);
1059 public void SetUseParameters(string[] parms) {
1060 if(parms.Length != 2) {
1061 Console.WriteLine("Error: wrong number of parameters");
1062 return;
1064 string parm = parms[1].ToUpper();
1065 if(parm.Equals("TRUE"))
1066 UseParameters = true;
1067 else if(parm.Equals("FALSE"))
1068 UseParameters = false;
1069 else
1070 Console.WriteLine("Error: invalid parameter.");
1074 public void SetUseSimpleReader(string[] parms) {
1075 if(parms.Length != 2) {
1076 Console.WriteLine("Error: wrong number of parameters");
1077 return;
1079 string parm = parms[1].ToUpper();
1080 if(parm.Equals("TRUE"))
1081 UseSimpleReader = true;
1082 else if(parm.Equals("FALSE"))
1083 UseSimpleReader = false;
1084 else
1085 Console.WriteLine("Error: invalid parameter.");
1088 public void SetupSilentMode(string[] parms) {
1089 if(parms.Length != 2) {
1090 Console.WriteLine("Error: wrong number of parameters");
1091 return;
1093 string parm = parms[1].ToUpper();
1094 if(parm.Equals("TRUE"))
1095 silent = true;
1096 else if(parm.Equals("FALSE"))
1097 silent = false;
1098 else
1099 Console.WriteLine("Error: invalid parameter.");
1102 public void SetInternalVariable(string[] parms) {
1103 if(parms.Length < 2) {
1104 Console.WriteLine("Error: wrong number of parameters.");
1105 return;
1107 string parm = parms[1];
1108 StringBuilder ps = new StringBuilder();
1110 for(int i = 2; i < parms.Length; i++)
1111 ps.Append(parms[i]);
1113 internalVariables[parm] = ps.ToString();
1116 public void UnSetInternalVariable(string[] parms) {
1117 if(parms.Length != 2) {
1118 Console.WriteLine("Error: wrong number of parameters.");
1119 return;
1121 string parm = parms[1];
1123 try {
1124 internalVariables.Remove(parm);
1126 catch(Exception e) {
1127 Console.WriteLine("Error: internal variable does not exist: " +
1128 e.Message);
1132 public void ShowInternalVariable(string[] parms) {
1133 string internalVariableValue = "";
1135 if(parms.Length != 2) {
1136 Console.WriteLine("Error: wrong number of parameters.");
1137 return;
1140 string parm = parms[1];
1142 if(GetInternalVariable(parm, out internalVariableValue) == true)
1143 Console.WriteLine("Internal Variable - Name: " +
1144 parm + " Value: " + internalVariableValue);
1147 public bool GetInternalVariable(string name, out string sValue) {
1148 sValue = "";
1149 bool valueReturned = false;
1151 try {
1152 if(internalVariables.ContainsKey(name) == true) {
1153 sValue = (string) internalVariables[name];
1154 valueReturned = true;
1156 else
1157 Console.WriteLine("Error: internal variable does not exist.");
1160 catch(Exception e) {
1161 Console.WriteLine("Error: internal variable does not exist: "+
1162 e.Message);
1164 return valueReturned;
1167 public void SetupExternalProvider(string[] parms) {
1168 if(parms.Length != 3) {
1169 Console.WriteLine("Error: Wrong number of parameters.");
1170 return;
1172 provider = "LOADEXTPROVIDER";
1173 providerAssembly = parms[1];
1174 providerConnectionClass = parms[2];
1177 public bool LoadExternalProvider() {
1178 string msg = "";
1180 bool success = false;
1182 // For example: for the MySQL provider in Mono.Data.MySql
1183 // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
1184 // \ConnectionString dbname=test
1185 // \open
1186 // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
1187 // \exenonquery
1188 // \close
1189 // \quit
1191 try {
1192 Console.WriteLine("Loading external provider...");
1193 Console.Out.Flush();
1195 Assembly ps = Assembly.Load(providerAssembly);
1196 conType = ps.GetType(providerConnectionClass);
1197 conn = (IDbConnection) Activator.CreateInstance(conType);
1198 success = true;
1200 Console.WriteLine("External provider loaded.");
1201 Console.Out.Flush();
1202 UseParameters = false;
1204 catch(FileNotFoundException f) {
1205 msg = "Error: unable to load the assembly of the provider: " +
1206 providerAssembly +
1207 " : " + f.Message;
1208 Console.WriteLine(msg);
1210 catch(Exception e) {
1211 msg = "Error: unable to load the assembly of the provider: " +
1212 providerAssembly +
1213 " : " + e.Message;
1214 Console.WriteLine(msg);
1216 return success;
1219 // used for outputting message, but if silent is set,
1220 // don't display
1221 public void OutputLine(string line) {
1222 if(silent == false)
1223 OutputData(line);
1226 // used for outputting the header columns of a result
1227 public void OutputHeader(string line) {
1228 if(showHeader == true)
1229 OutputData(line);
1232 // OutputData() - used for outputting data
1233 // if an output filename is set, then the data will
1234 // go to a file; otherwise, it will go to the Console.
1235 public void OutputData(string line) {
1236 if(outputFilestream == null)
1237 Console.WriteLine(line);
1238 else
1239 outputFilestream.WriteLine(line);
1242 // HandleCommand - handle SqlSharpCli commands entered
1243 public void HandleCommand(string entry) {
1244 string[] parms;
1246 parms = entry.Split(new char[1] {' '});
1247 string userCmd = parms[0].ToUpper();
1249 switch(userCmd) {
1250 case "\\PROVIDER":
1251 ChangeProvider(parms);
1252 break;
1253 case "\\CONNECTIONSTRING":
1254 ChangeConnectionString(entry);
1255 break;
1256 case "\\LOADEXTPROVIDER":
1257 SetupExternalProvider(parms);
1258 break;
1259 case "\\OPEN":
1260 OpenDataSource();
1261 break;
1262 case "\\CLOSE":
1263 CloseDataSource();
1264 break;
1265 case "\\S":
1266 SetupSilentMode(parms);
1267 break;
1268 case "\\E":
1269 case "\\EXEQUERY":
1270 case "\\EXEREADER":
1271 case "\\EXECUTE":
1272 // Execute SQL Commands or Queries
1273 if(conn == null)
1274 Console.WriteLine("Error: connection is not Open.");
1275 else if(conn.State == ConnectionState.Closed)
1276 Console.WriteLine("Error: connection is not Open.");
1277 else {
1278 if(build == null)
1279 Console.WriteLine("Error: SQL Buffer is empty.");
1280 else {
1281 buff = build.ToString();
1282 ExecuteSql(buff);
1284 build = null;
1286 break;
1287 case "\\EXENONQUERY":
1288 if(conn == null)
1289 Console.WriteLine("Error: connection is not Open.");
1290 else if(conn.State == ConnectionState.Closed)
1291 Console.WriteLine("Error: connection is not Open.");
1292 else {
1293 if(build == null)
1294 Console.WriteLine("Error: SQL Buffer is empty.");
1295 else {
1296 buff = build.ToString();
1297 ExecuteSqlNonQuery(buff);
1299 build = null;
1301 break;
1302 case "\\EXESCALAR":
1303 if(conn == null)
1304 Console.WriteLine("Error: connection is not Open.");
1305 else if(conn.State == ConnectionState.Closed)
1306 Console.WriteLine("Error: connection is not Open.");
1307 else {
1308 if(build == null)
1309 Console.WriteLine("Error: SQL Buffer is empty.");
1310 else {
1311 buff = build.ToString();
1312 ExecuteSqlScalar(buff);
1314 build = null;
1316 break;
1317 case "\\EXEXML":
1318 // \exexml OUTPUT_FILENAME
1319 if(conn == null)
1320 Console.WriteLine("Error: connection is not Open.");
1321 else if(conn.State == ConnectionState.Closed)
1322 Console.WriteLine("Error: connection is not Open.");
1323 else {
1324 if(build == null)
1325 Console.WriteLine("Error: SQL Buffer is empty.");
1326 else {
1327 buff = build.ToString();
1328 ExecuteSqlXml(buff, parms);
1330 build = null;
1332 break;
1333 case "\\F":
1334 SetupInputCommandsFile(parms);
1335 break;
1336 case "\\O":
1337 SetupOutputResultsFile(parms);
1338 break;
1339 case "\\LOAD":
1340 // Load file into SQL buffer: \load FILENAME
1341 LoadBufferFromFile(parms);
1342 break;
1343 case "\\SAVE":
1344 // Save SQL buffer to file: \save FILENAME
1345 SaveBufferToFile(parms);
1346 break;
1347 case "\\H":
1348 case "\\HELP":
1349 // Help
1350 ShowHelp();
1351 break;
1352 case "\\DEFAULTS":
1353 // show the defaults for provider and connection strings
1354 ShowDefaults();
1355 break;
1356 case "\\Q":
1357 case "\\QUIT":
1358 // Quit
1359 break;
1360 case "\\CLEAR":
1361 case "\\RESET":
1362 case "\\R":
1363 // reset (clear) the query buffer
1364 build = null;
1365 break;
1366 case "\\SET":
1367 // sets internal variable
1368 // \set name value
1369 SetInternalVariable(parms);
1370 break;
1371 case "\\UNSET":
1372 // deletes internal variable
1373 // \unset name
1374 UnSetInternalVariable(parms);
1375 break;
1376 case "\\VARIABLE":
1377 ShowInternalVariable(parms);
1378 break;
1379 case "\\PRINT":
1380 if(build == null)
1381 Console.WriteLine("SQL Buffer is empty.");
1382 else
1383 Console.WriteLine("SQL Bufer:\n" + buff);
1384 break;
1385 case "\\USEPARAMETERS":
1386 SetUseParameters(parms);
1387 break;
1388 case "\\USESIMPLEREADER":
1389 SetUseSimpleReader(parms);
1390 break;
1391 default:
1392 // Error
1393 Console.WriteLine("Error: Unknown user command.");
1394 break;
1398 public void DealWithArgs(string[] args) {
1399 for(int a = 0; a < args.Length; a++) {
1400 if(args[a].Substring(0,1).Equals("-")) {
1401 string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
1402 switch(arg) {
1403 case "S":
1404 silent = true;
1405 break;
1406 case "F":
1407 if(a + 1 >= args.Length)
1408 Console.WriteLine("Error: Missing FILENAME for -f switch");
1409 else {
1410 inputFilename = args[a + 1];
1411 inputFilestream = new StreamReader(inputFilename);
1413 break;
1414 case "O":
1415 if(a + 1 >= args.Length)
1416 Console.WriteLine("Error: Missing FILENAME for -o switch");
1417 else {
1418 outputFilename = args[a + 1];
1419 outputFilestream = new StreamWriter(outputFilename);
1421 break;
1422 default:
1423 Console.WriteLine("Error: Unknow switch: " + args[a]);
1424 break;
1430 public string ReadSqlSharpCommand() {
1431 string entry = "";
1433 if(inputFilestream == null) {
1434 Console.Write("\nSQL# ");
1435 entry = Console.ReadLine();
1437 else {
1438 try {
1439 entry = inputFilestream.ReadLine();
1440 if(entry == null) {
1441 Console.WriteLine("Executing SQL# Commands from file done.");
1444 catch(Exception e) {
1445 Console.WriteLine("Error: Reading command from file: " +
1446 e.Message);
1448 Console.Write("\nSQL# ");
1449 entry = Console.ReadLine();
1451 return entry;
1454 public void Run(string[] args) {
1456 DealWithArgs(args);
1458 string entry = "";
1459 build = null;
1461 if(silent == false) {
1462 Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
1463 Console.WriteLine("for Mono.Data. See http://www.go-mono.com/ for more details.\n");
1465 StartupHelp();
1466 ShowDefaults();
1469 while(entry.ToUpper().Equals("\\Q") == false &&
1470 entry.ToUpper().Equals("\\QUIT") == false) {
1472 while((entry = ReadSqlSharpCommand()) == "") {}
1475 if(entry.Substring(0,1).Equals("\\")) {
1476 HandleCommand(entry);
1478 else if(entry.IndexOf(";") >= 0) {
1479 // most likely the end of SQL Command or Query found
1480 // execute the SQL
1481 if(conn == null)
1482 Console.WriteLine("Error: connection is not Open.");
1483 else if(conn.State == ConnectionState.Closed)
1484 Console.WriteLine("Error: connection is not Open.");
1485 else {
1486 if(build == null) {
1487 build = new StringBuilder();
1489 build.Append(entry);
1490 //build.Append("\n");
1491 buff = build.ToString();
1492 ExecuteSql(buff);
1493 build = null;
1496 else {
1497 // most likely a part of a SQL Command or Query found
1498 // append this part of the SQL
1499 if(build == null) {
1500 build = new StringBuilder();
1502 build.Append(entry + "\n");
1503 buff = build.ToString();
1506 CloseDataSource();
1507 if(outputFilestream != null)
1508 outputFilestream.Close();
1512 public enum BindVariableCharacter {
1513 Colon, // ':' - named parameter - :name
1514 At, // '@' - named parameter - @name
1515 QuestionMark, // '?' - positioned parameter - ?
1516 SquareBrackets // '[]' - delimited named parameter - [name]
1519 public class ParametersBuilder {
1521 private BindVariableCharacter bindCharSetting;
1522 private char bindChar;
1523 private IDataParameterCollection parms;
1524 private string sql;
1525 private IDbCommand cmd;
1527 private void SetBindCharacter() {
1528 switch(bindCharSetting) {
1529 case BindVariableCharacter.Colon:
1530 bindChar = ':';
1531 break;
1532 case BindVariableCharacter.At:
1533 bindChar = '@';
1534 break;
1535 case BindVariableCharacter.SquareBrackets:
1536 bindChar = '[';
1537 break;
1538 case BindVariableCharacter.QuestionMark:
1539 bindChar = '?';
1540 break;
1544 public ParametersBuilder(IDbCommand command, BindVariableCharacter bindVarChar) {
1545 cmd = command;
1546 sql = cmd.CommandText;
1547 parms = cmd.Parameters;
1548 bindCharSetting = bindVarChar;
1549 SetBindCharacter();
1552 public char ParameterMarkerCharacter {
1553 get {
1554 return bindChar;
1558 public int ParseParameters() {
1560 int numParms = 0;
1562 IDataParameterCollection parms = cmd.Parameters;
1564 char[] chars = sql.ToCharArray();
1565 bool bStringConstFound = false;
1567 for(int i = 0; i < chars.Length; i++) {
1568 if(chars[i] == '\'') {
1569 if(bStringConstFound == true)
1570 bStringConstFound = false;
1571 else
1572 bStringConstFound = true;
1574 else if(chars[i] == bindChar &&
1575 bStringConstFound == false) {
1576 if(bindChar != '?') {
1577 StringBuilder parm = new StringBuilder();
1578 i++;
1579 if(bindChar.Equals('[')) {
1580 bool endingBracketFound = false;
1581 while(i <= chars.Length) {
1582 char ch;
1583 if(i == chars.Length)
1584 ch = ' '; // a space
1585 else
1586 ch = chars[i];
1588 if(Char.IsLetterOrDigit(ch) || ch == ' ') {
1589 parm.Append(ch);
1591 else if (ch == ']') {
1592 endingBracketFound = true;
1593 string p = parm.ToString();
1594 AddParameter(p);
1595 numParms ++;
1596 break;
1598 else throw new Exception("SQL Parser Error: Invalid character in parameter name");
1599 i++;
1601 i--;
1602 if(endingBracketFound == false)
1603 throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
1605 else {
1606 while(i <= chars.Length) {
1607 char ch;
1608 if(i == chars.Length)
1609 ch = ' '; // a space
1610 else
1611 ch = chars[i];
1613 if(Char.IsLetterOrDigit(ch)) {
1614 parm.Append(ch);
1616 else {
1618 string p = parm.ToString();
1619 AddParameter(p);
1620 numParms ++;
1621 break;
1623 i++;
1625 i--;
1628 else {
1629 // placeholder paramaeter for ?
1630 string p = numParms.ToString();
1631 AddParameter(p);
1632 numParms ++;
1636 return numParms;
1639 public void AddParameter (string p) {
1640 Console.WriteLine("Add Parameter: " + p);
1641 if(parms.Contains(p) == false) {
1642 IDataParameter prm = cmd.CreateParameter();
1643 prm.ParameterName = p;
1644 prm.Direction = ParameterDirection.Input;
1645 prm.DbType = DbType.String; // default
1646 prm.Value = ""; // default
1647 cmd.Parameters.Add(prm);
1652 public class SqlSharpDriver {
1653 public static void Main(string[] args) {
1654 SqlSharpCli sqlCommandLineEngine = new SqlSharpCli();
1655 sqlCommandLineEngine.Run(args);