2 // SqlSharpCli.cs - main driver for SQL# Command Line Interface
3 // found in mcs/tools/SqlSharp
5 // SQL# is a SQL query tool allowing to enter queries and get
6 // back results displayed to the console, to an html file, or
7 // an xml file. SQL non-query commands and aggregates can be
10 // Can be used to test the various data providers in Mono
11 // and data providers external to Mono.
13 // There is a GTK# version of SQL#
14 // found in mcs/tools/SqlSharp/gui/gtk-sharp
16 // This program is included in Mono and is licenced under the GPL.
17 // http://www.fsf.org/licenses/gpl.html
19 // For more information about Mono,
20 // visit http://www.go-mono.com/
22 // To build SqlSharpCli.cs on Linux:
23 // $ mcs SqlSharpCli.cs -r System.Data.dll
25 // To build SqlSharpCli.exe on Windows:
26 // $ mono c:/cygwin/home/someuser/mono/install/bin/mcs.exe \
27 // SqlSharpCli.cs -r System.Data.dll
30 // $ mono SqlSharpCli.exe
33 // $ mint SqlSharpCli.exe
35 // To run batch commands and get the output, do something like:
36 // $ cat commands.txt | mono SqlSharpCli.exe > results.txt
39 // Daniel Morgan <danmorg@sc.rr.com>
41 // (C)Copyright 2002 Daniel Morgan
45 using System.Collections;
47 using System.Data.Common;
48 using System.Data.Odbc;
49 using System.Data.OleDb;
50 using System.Data.SqlClient;
52 using System.Reflection;
53 using System.Runtime.Remoting;
56 namespace Mono.Data.SqlSharp {
58 public enum FileFormat {
66 // SQL Sharp - Command Line Interface
67 public class SqlSharpCli {
70 private bool UseParameters = true;
71 private bool UseSimpleReader = false;
73 private IDbConnection conn = null;
75 private string provider = ""; // name of internal provider
76 // {OleDb,SqlClient,MySql,Odbc,Oracle,
77 // PostgreSql,SqlLite,Sybase,Tds} however, it
78 // can be set to LOADEXTPROVIDER to load an external provider
79 private string providerAssembly = "";
80 // filename of assembly
81 // for example: "Mono.Data.MySql"
82 private string providerConnectionClass = "";
84 // in the provider assembly that implements the IDbConnection
85 // interface. for example: "Mono.Data.MySql.MySqlConnection"
87 private StringBuilder build = null; // SQL string to build
88 private string buff = ""; // SQL string buffer
90 private string connectionString = "";
92 private string inputFilename = "";
93 private string outputFilename = "";
94 private StreamReader inputFilestream = null;
95 private StreamWriter outputFilestream = null;
97 private FileFormat outputFileFormat = FileFormat.Html;
99 private bool silent = false;
100 private bool showHeader = true;
102 private Hashtable internalVariables = new Hashtable();
104 // DisplayResult - used to Read() display a result set
105 // called by DisplayData()
106 public void DisplayResult(IDataReader reader, DataTable schemaTable) {
108 const string zero = "0";
109 StringBuilder column = null;
110 StringBuilder line = null;
111 StringBuilder hdrUnderline = null;
119 char spacingChar = ' '; // a space
120 char underlineChar = '='; // an equal sign
122 string dataType; // .NET Type
124 string dataTypeName; // native Database type
125 DataRow row; // schema row
127 line = new StringBuilder();
128 hdrUnderline = new StringBuilder();
130 OutputLine("Fields in Query Result: " +
134 for(c = 0; c < schemaTable.Rows.Count; c++) {
136 DataRow schemaRow = schemaTable.Rows[c];
137 string columnHeader = (string) schemaRow["ColumnName"];
138 if(columnHeader.Equals(""))
139 columnHeader = "?column?";
140 if(columnHeader.Length > 32)
141 columnHeader = columnHeader.Substring(0,32);
144 columnSize = (int) schemaRow["ColumnSize"];
145 theType = (Type) schemaRow["DataType"];
146 dataType = theType.ToString();
147 dataTypeName = reader.GetDataTypeName(c);
150 case "System.DateTime":
153 case "System.Boolean":
158 if(provider.Equals("POSTGRESQL") ||
159 provider.Equals("MYSQL"))
160 if(dataTypeName.Equals("text"))
161 columnSize = 32; // text will be truncated to 32
163 hdrLen = (columnHeader.Length > columnSize) ?
164 columnHeader.Length : columnSize;
171 line.Append(columnHeader);
172 if(columnHeader.Length < hdrLen) {
173 spacing = hdrLen - columnHeader.Length;
174 line.Append(spacingChar, spacing);
176 hdrUnderline.Append(underlineChar, hdrLen);
179 hdrUnderline.Append(" ");
181 OutputHeader(line.ToString());
184 OutputHeader(hdrUnderline.ToString());
191 while(reader.Read()) {
194 line = new StringBuilder();
195 for(c = 0; c < reader.FieldCount; c++) {
197 string dataValue = "";
198 column = new StringBuilder();
201 row = schemaTable.Rows[c];
202 string colhdr = (string) row["ColumnName"];
203 if(colhdr.Equals(""))
205 if(colhdr.Length > 32)
206 colhdr = colhdr.Substring(0, 32);
208 columnSize = (int) row["ColumnSize"];
209 theType = (Type) row["DataType"];
210 dataType = theType.ToString();
212 dataTypeName = reader.GetDataTypeName(c);
215 case "System.DateTime":
218 case "System.Boolean":
223 if(provider.Equals("POSTGRESQL") ||
224 provider.Equals("MYSQL"))
225 if(dataTypeName.Equals("text"))
226 columnSize = 32; // text will be truncated to 32
228 columnSize = (colhdr.Length > columnSize) ?
229 colhdr.Length : columnSize;
238 if(reader.IsDBNull(c)) {
245 if(dataType.Equals("System.DateTime")) {
246 // display date in ISO format
247 // "YYYY-MM-DD HH:MM:SS"
\r
248 dt = reader.GetDateTime(c);
\r
249 sb = new StringBuilder();
\r
252 sb.Append("000" + dt.Year);
\r
253 else if(dt.Year < 100)
\r
254 sb.Append("00" + dt.Year);
\r
255 else if(dt.Year < 1000)
\r
256 sb.Append("0" + dt.Year);
\r
258 sb.Append(dt.Year);
\r
262 sb.Append(zero + dt.Month);
\r
264 sb.Append(dt.Month);
\r
268 sb.Append(zero + dt.Day);
\r
274 sb.Append(zero + dt.Hour);
\r
276 sb.Append(dt.Hour);
\r
280 sb.Append(zero + dt.Minute);
\r
282 sb.Append(dt.Minute);
\r
286 sb.Append(zero + dt.Second);
\r
288 sb.Append(dt.Second);
\r
290 dataValue = sb.ToString();
\r
293 dataValue = reader.GetValue(c).ToString();
296 dataLen = dataValue.Length;
302 dataValue = dataValue.Substring(0,32);
306 columnSize = columnSize > dataLen ? columnSize : dataLen;
310 if(columnSize < colhdr.Length) {
311 spacing = colhdr.Length - columnSize;
312 column.Append(spacingChar, spacing);
314 if(dataLen < columnSize) {
315 spacing = columnSize - dataLen;
316 column.Append(spacingChar, spacing);
321 case "System.Single":
322 case "System.Double":
323 case "System.Decimal":
324 outData = column.ToString() + dataValue;
327 outData = dataValue + column.ToString();
334 line.Append(outData);
337 OutputData(line.ToString());
340 OutputLine("\nRows retrieved: " + rows.ToString());
343 public void OutputDataToHtmlFile(IDataReader rdr, DataTable dt) {
345 StringBuilder strHtml = new StringBuilder();
\r
347 strHtml.Append("<html> \n <head> <title>");
\r
348 strHtml.Append("Results");
\r
349 strHtml.Append("</title> </head>");
\r
350 strHtml.Append("<body>");
\r
351 strHtml.Append("<h1> Results </h1>");
\r
352 strHtml.Append("<table border=1>");
\r
354 outputFilestream.WriteLine(strHtml.ToString());
\r
357 strHtml = new StringBuilder();
\r
359 strHtml.Append("<tr>");
\r
360 foreach (DataRow schemaRow in dt.Rows) {
\r
361 strHtml.Append("<td> <b>");
\r
362 object dataObj = schemaRow["ColumnName"];
\r
363 string sColumnName = dataObj.ToString();
\r
364 strHtml.Append(sColumnName);
\r
365 strHtml.Append("</b> </td>");
\r
367 strHtml.Append("</tr>");
\r
368 outputFilestream.WriteLine(strHtml.ToString());
\r
372 string dataValue = "";
\r
374 while(rdr.Read()) {
\r
375 strHtml = new StringBuilder();
\r
377 strHtml.Append("<tr>");
\r
378 for(col = 0; col < rdr.FieldCount; col++) {
\r
381 if(rdr.IsDBNull(col) == true)
\r
382 dataValue = "NULL";
\r
384 object obj = rdr.GetValue(col);
\r
385 dataValue = obj.ToString();
\r
387 strHtml.Append("<td>");
\r
388 strHtml.Append(dataValue);
\r
389 strHtml.Append("</td>");
\r
391 strHtml.Append("\t\t</tr>");
\r
392 outputFilestream.WriteLine(strHtml.ToString());
\r
395 outputFilestream.WriteLine(" </table> </body> \n </html>");
\r
399 // DisplayData - used to display any Result Sets
400 // from execution of SQL SELECT Query or Queries
401 // called by DisplayData.
402 // ExecuteSql() only calls this function
403 // for a Query, it does not get
405 public void DisplayData(IDataReader reader) {
407 DataTable schemaTable = null;
410 OutputLine("Display any result sets...");
413 // by Default, SqlDataReader has the
414 // first Result set if any
417 OutputLine("Display the result set " + ResultSet);
419 schemaTable = reader.GetSchemaTable();
421 if(reader.FieldCount > 0) {
422 // SQL Query (SELECT)
423 // RecordsAffected -1 and DataTable has a reference
424 OutputQueryResult(reader, schemaTable);
426 else if(reader.RecordsAffected >= 0) {
427 // SQL Command (INSERT, UPDATE, or DELETE)
428 // RecordsAffected >= 0
429 Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
432 // SQL Command (not INSERT, UPDATE, nor DELETE)
433 // RecordsAffected -1 and DataTable has a null reference
434 Console.WriteLine("SQL Command Executed.");
437 // get next result set (if anymore is left)
438 } while(reader.NextResult());
441 // display the result in a simple way
442 // new ADO.NET providers may have not certain
443 // things implemented yet, such as, TableSchema
445 public void DisplayDataSimple(IDataReader reader) {
448 Console.WriteLine("Reading Data using simple reader...");
\r
449 while(reader.Read()){
\r
451 Console.WriteLine("Row: " + row);
\r
452 for(int col = 0; col < reader.FieldCount; col++) {
\r
453 Console.WriteLine(" Field: " + col);
\r
454 //string dname = reader.GetName(col);
\r
455 //Console.WriteLine(" Name: " + dname);
\r
456 string dvalue = reader.GetValue(col).ToString();
\r
457 Console.WriteLine(" Value: " + dvalue);
\r
460 Console.WriteLine("\n" + row + " ROWS RETRIEVED\n");
463 public void OutputQueryResult(IDataReader dreader, DataTable dtable) {
464 if(outputFilestream == null) {
465 DisplayResult(dreader, dtable);
468 switch(outputFileFormat) {
469 case FileFormat.Normal:
470 DisplayResult(dreader, dtable);
472 case FileFormat.Html:
473 OutputDataToHtmlFile(dreader, dtable);
476 Console.WriteLine("Error: Output data file format not supported.");
482 public void BuildParameters(IDbCommand cmd) {
483 if(UseParameters == true) {
485 ParametersBuilder parmsBuilder =
\r
486 new ParametersBuilder(cmd,
\r
487 BindVariableCharacter.Colon);
\r
489 Console.WriteLine("Get Parameters (if any)...");
\r
490 parmsBuilder.ParseParameters();
\r
491 IList parms = (IList) cmd.Parameters;
\r
493 Console.WriteLine("Print each parm...");
\r
494 for(int p = 0; p < parms.Count; p++) {
\r
495 string theParmName;
\r
497 IDataParameter prm = (IDataParameter) parms[p];
\r
498 theParmName = prm.ParameterName;
\r
500 string inValue = "";
\r
502 if(parmsBuilder.ParameterMarkerCharacter == '?') {
\r
503 Console.Write("Enter Parameter " +
\r
504 (p + 1).ToString() +
\r
506 inValue = Console.ReadLine();
\r
507 prm.Value = inValue;
\r
510 found = GetInternalVariable(theParmName, out inValue);
\r
511 if(found == true) {
\r
512 prm.Value = inValue;
\r
515 Console.Write("Enter Parameter " + (p + 1).ToString() +
\r
516 ": " + theParmName + ": ");
\r
517 inValue = Console.ReadLine();
\r
518 prm.Value = inValue;
\r
526 // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
527 public void ExecuteSql(string sql) {
530 Console.WriteLine("Execute SQL: " + sql);
532 IDbCommand cmd = null;
533 IDataReader reader = null;
535 cmd = conn.CreateCommand();
537 // set command properties
538 cmd.CommandType = CommandType.Text;
539 cmd.CommandText = sql;
540 cmd.Connection = conn;
542 BuildParameters(cmd);
545 reader = cmd.ExecuteReader();
547 if(UseSimpleReader == false)
550 DisplayDataSimple(reader);
556 msg = "Error: " + e.Message;
557 Console.WriteLine(msg);
558 //if(reader != null) {
559 // if(reader.IsClosed == false)
570 // ExecuteSql - Execute the SQL Commands (no SELECTs)
571 public void ExecuteSqlNonQuery(string sql) {
574 Console.WriteLine("Execute SQL Non Query: " + sql);
576 IDbCommand cmd = null;
577 int rowsAffected = -1;
579 cmd = conn.CreateCommand();
581 // set command properties
582 cmd.CommandType = CommandType.Text;
583 cmd.CommandText = sql;
584 cmd.Connection = conn;
586 BuildParameters(cmd);
589 rowsAffected = cmd.ExecuteNonQuery();
591 Console.WriteLine("Rows affected: " + rowsAffected);
594 msg = "Error: " + e.Message;
595 Console.WriteLine(msg);
603 public void ExecuteSqlScalar(string sql) {
606 Console.WriteLine("Execute SQL Scalar: " + sql);
608 IDbCommand cmd = null;
609 string retrievedValue = "";
611 cmd = conn.CreateCommand();
613 // set command properties
614 cmd.CommandType = CommandType.Text;
615 cmd.CommandText = sql;
616 cmd.Connection = conn;
618 BuildParameters(cmd);
621 retrievedValue = (string) cmd.ExecuteScalar().ToString();
622 Console.WriteLine("Retrieved value: " + retrievedValue);
625 msg = "Error: " + e.Message;
626 Console.WriteLine(msg);
634 public void ExecuteSqlXml(string sql, string[] parms) {
635 string filename = "";
637 if(parms.Length != 2) {
638 Console.WriteLine("Error: wrong number of parameters");
644 catch(Exception e) {
\r
645 Console.WriteLine("Error: Unable to setup output results file. " +
\r
651 Console.WriteLine("Execute SQL XML: " + sql);
653 IDbCommand cmd = null;
655 cmd = conn.CreateCommand();
657 // set command properties
658 cmd.CommandType = CommandType.Text;
659 cmd.CommandText = sql;
660 cmd.Connection = conn;
662 BuildParameters(cmd);
664 Console.WriteLine("Creating new DataSet...");
665 DataSet dataSet = new DataSet ();
667 Console.WriteLine("Creating new provider DataAdapter...");
668 DbDataAdapter adapter = CreateNewDataAdapter (cmd, conn);
670 Console.WriteLine("Filling DataSet via Data Adapter...");
671 adapter.Fill (dataSet);
673 Console.WriteLine ("Write DataSet to XML file: " +
675 dataSet.WriteXml (filename);
677 Console.WriteLine ("Done.");
679 catch(Exception exexml) {
680 Console.WriteLine("Error: Execute SQL XML Failure: " +
685 public DbDataAdapter CreateNewDataAdapter (IDbCommand command,
686 IDbConnection connection) {
688 DbDataAdapter adapter = null;
692 adapter = (DbDataAdapter) new OdbcDataAdapter ();
695 adapter = (DbDataAdapter) new OleDbDataAdapter ();
698 adapter = (DbDataAdapter) new SqlDataAdapter ();
700 case "LOADEXTPROVIDER":
701 adapter = CreateExternalDataAdapter (command, connection);
706 Console.WriteLine("Error: Data Adapter not found in provider.");
709 IDbDataAdapter dbAdapter = (IDbDataAdapter) adapter;
710 dbAdapter.SelectCommand = command;
715 public DbDataAdapter CreateExternalDataAdapter (IDbCommand command,
716 IDbConnection connection) {
718 DbDataAdapter adapter = null;
720 Assembly ass = Assembly.Load (providerAssembly);
721 Type [] types = ass.GetTypes ();
722 foreach (Type t in types) {
723 if (t.IsSubclassOf (typeof(System.Data.Common.DbDataAdapter))) {
724 adapter = (DbDataAdapter) Activator.CreateInstance (t);
731 // like ShowHelp - but only show at the beginning
732 // only the most important commands are shown
733 // like help and quit
734 public void StartupHelp() {
735 Console.WriteLine(@"Type: \Q to quit");
736 Console.WriteLine(@" \ConnectionString to set the ConnectionString");
737 Console.WriteLine(@" \Provider to set the Provider:");
738 Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
739 Console.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds)");
740 Console.WriteLine(@" \Open to open the connection");
741 Console.WriteLine(@" \Close to close the connection");
742 Console.WriteLine(@" \e to execute SQL query (SELECT)");
743 Console.WriteLine(@" \h to show help (all commands).");
744 Console.WriteLine(@" \defaults to show default variables.");
748 // ShowHelp - show the help - command a user can enter
749 public void ShowHelp() {
750 Console.WriteLine("");
751 Console.WriteLine(@"Type: \Q to quit");
752 Console.WriteLine(@" \ConnectionString to set the ConnectionString");
753 Console.WriteLine(@" \Provider to set the Provider:");
754 Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
755 Console.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds}");
756 Console.WriteLine(@" \Open to open the connection");
757 Console.WriteLine(@" \Close to close the connection");
758 Console.WriteLine(@" \e to execute SQL query (SELECT)");
759 Console.WriteLine(@" \exenonquery to execute an SQL non query (not a SELECT).");
760 Console.WriteLine(@" \exescalar to execute SQL to get a single row and single column.");
761 Console.WriteLine(@" \exexml FILENAME to execute SQL and save output to XML file.");
762 Console.WriteLine(@" \f FILENAME to read a batch of SQL# commands from file.");
763 Console.WriteLine(@" \o FILENAME to write result of commands executed to file.");
764 Console.WriteLine(@" \load FILENAME to load from file SQL commands into SQL buffer.");
765 Console.WriteLine(@" \save FILENAME to save SQL commands from SQL buffer to file.");
766 Console.WriteLine(@" \h to show help (all commands).");
767 Console.WriteLine(@" \defaults to show default variables, such as,");
768 Console.WriteLine(@" Provider and ConnectionString.");
769 Console.WriteLine(@" \s {TRUE, FALSE} to silent messages.");
770 Console.WriteLine(@" \r to reset or clear the query buffer.");
772 Console.WriteLine(@" \set NAME VALUE to set an internal variable.");
773 Console.WriteLine(@" \unset NAME to remove an internal variable.");
774 Console.WriteLine(@" \variable NAME to display the value of an internal variable.");
775 Console.WriteLine(@" \loadextprovider ASSEMBLY CLASS to load the provider");
776 Console.WriteLine(@" use the complete name of its assembly and");
777 Console.WriteLine(@" its Connection class.");
778 Console.WriteLine(@" \print - show what's in the SQL buffer now.");
779 Console.WriteLine(@" \UseParameters (TRUE,FALSE) to use parameters when executing SQL.");
780 Console.WriteLine(@" \UseSimpleReader (TRUE,FALSE) to use simple reader when displaying results.");
784 public bool WaitForEnterKey() {
785 Console.Write("Waiting... Press Enter key to continue. ");
786 string entry = Console.ReadLine();
787 if (entry.ToUpper() == "Q")
792 // ShowDefaults - show defaults for connection variables
793 public void ShowDefaults() {
795 if(provider.Equals(""))
796 Console.WriteLine("Provider is not set.");
798 Console.WriteLine("The default Provider is " + provider);
799 if(provider.Equals("LOADEXTPROVIDER")) {
800 Console.WriteLine(" Assembly: " +
802 Console.WriteLine(" Connection Class: " +
803 providerConnectionClass);
807 if(connectionString.Equals(""))
808 Console.WriteLine("ConnectionString is not set.");
810 Console.WriteLine("The default ConnectionString is: ");
811 Console.WriteLine(" \"" + connectionString + "\"");
816 // OpenDataSource - open connection to the data source
817 public void OpenDataSource() {
820 Console.WriteLine("Attempt to open connection...");
825 conn = new OdbcConnection();
828 conn = new OleDbConnection();
831 conn = new SqlConnection();
833 case "LOADEXTPROVIDER":
834 if(LoadExternalProvider() == false)
838 Console.WriteLine("Error: Bad argument or provider not supported.");
843 msg = "Error: Unable to create Connection object because: " +
845 Console.WriteLine(msg);
849 conn.ConnectionString = connectionString;
853 if(conn.State == ConnectionState.Open)
854 Console.WriteLine("Open was successfull.");
857 msg = "Exception Caught Opening. " + e.Message;
858 Console.WriteLine(msg);
863 // CloseDataSource - close the connection to the data source
864 public void CloseDataSource() {
868 Console.WriteLine("Attempt to Close...");
871 Console.WriteLine("Close was successfull.");
874 msg = "Exeception Caught Closing. " + e.Message;
875 Console.WriteLine(msg);
881 // ChangeProvider - change the provider string variable
882 public void ChangeProvider(string[] parms) {
886 if(parms.Length == 2) {
887 string parm = parms[1].ToUpper();
890 extp = new string[3] {
892 "Mono.Data.TdsClient",
893 "Mono.Data.TdsClient.TdsConnection"};
894 SetupExternalProvider(extp);
895 UseParameters = false;
896 UseSimpleReader = false;
899 extp = new string[3] {
901 "Mono.Data.SybaseClient",
902 "Mono.Data.SybaseClient.SybaseConnection"};
903 SetupExternalProvider(extp);
904 UseParameters = false;
905 UseSimpleReader = false;
908 extp = new string[3] {
911 "Mono.Data.MySql.MySqlConnection"};
912 SetupExternalProvider(extp);
913 UseParameters = false;
914 UseSimpleReader = false;
917 extp = new string[3] {
919 "Mono.Data.SqliteClient",
920 "Mono.Data.SqliteClient.SqliteConnection"};
921 SetupExternalProvider(extp);
922 UseParameters = false;
923 UseSimpleReader = true;
926 UseParameters = false;
927 UseSimpleReader = false;
931 UseParameters = false;
932 UseSimpleReader = false;
936 UseParameters = false;
937 UseSimpleReader = true;
941 extp = new string[3] {
943 "Mono.Data.PostgreSqlClient",
944 "Mono.Data.PostgreSqlClient.PgSqlConnection"};
945 SetupExternalProvider(extp);
946 UseParameters = false;
947 UseSimpleReader = true;
950 Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
953 Console.WriteLine("The default Provider is " + provider);
954 if(provider.Equals("LOADEXTPROVIDER")) {
955 Console.WriteLine(" Assembly: " +
957 Console.WriteLine(" Connection Class: " +
958 providerConnectionClass);
962 Console.WriteLine("Error: provider only has one parameter.");
965 // ChangeConnectionString - change the connection string variable
966 public void ChangeConnectionString(string entry) {
968 if(entry.Length > 18)
969 connectionString = entry.Substring(18, entry.Length - 18);
971 connectionString = "";
974 public void SetupOutputResultsFile(string[] parms) {
\r
975 if(parms.Length != 2) {
976 Console.WriteLine("Error: wrong number of parameters");
980 outputFilestream = new StreamWriter(parms[1]);
982 catch(Exception e) {
\r
983 Console.WriteLine("Error: Unable to setup output results file. " +
\r
989 public void SetupInputCommandsFile(string[] parms) {
990 if(parms.Length != 2) {
991 Console.WriteLine("Error: wrong number of parameters");
995 inputFilestream = new StreamReader(parms[1]);
997 catch(Exception e) {
\r
998 Console.WriteLine("Error: Unable to setup input commmands file. " +
\r
1004 public void LoadBufferFromFile(string[] parms) {
1005 if(parms.Length != 2) {
1006 Console.WriteLine("Error: wrong number of parameters");
1009 string inFilename = parms[1];
1011 StreamReader sr = new StreamReader( inFilename);
\r
1012 StringBuilder buffer = new StringBuilder();
\r
1015 while((NextLine = sr.ReadLine()) != null) {
\r
1016 buffer.Append(NextLine);
\r
1017 buffer.Append("\n");
\r
1020 buff = buffer.ToString();
\r
1022 build = new StringBuilder();
\r
1023 build.Append(buff);
\r
1025 catch(Exception e) {
\r
1026 Console.WriteLine("Error: Unable to read file into SQL Buffer. " +
\r
1031 public void SaveBufferToFile(string[] parms) {
1032 if(parms.Length != 2) {
1033 Console.WriteLine("Error: wrong number of parameters");
1036 string outFilename = parms[1];
1038 StreamWriter sw = new StreamWriter(outFilename);
\r
1039 sw.WriteLine(buff);
\r
1042 catch(Exception e) {
1043 Console.WriteLine("Error: Could not save SQL Buffer to file." +
1048 public void SetUseParameters(string[] parms) {
1049 if(parms.Length != 2) {
1050 Console.WriteLine("Error: wrong number of parameters");
1053 string parm = parms[1].ToUpper();
1054 if(parm.Equals("TRUE"))
1055 UseParameters = true;
1056 else if(parm.Equals("FALSE"))
1057 UseParameters = false;
1059 Console.WriteLine("Error: invalid parameter.");
1063 public void SetUseSimpleReader(string[] parms) {
1064 if(parms.Length != 2) {
1065 Console.WriteLine("Error: wrong number of parameters");
1068 string parm = parms[1].ToUpper();
1069 if(parm.Equals("TRUE"))
1070 UseSimpleReader = true;
1071 else if(parm.Equals("FALSE"))
1072 UseSimpleReader = false;
1074 Console.WriteLine("Error: invalid parameter.");
1077 public void SetupSilentMode(string[] parms) {
1078 if(parms.Length != 2) {
1079 Console.WriteLine("Error: wrong number of parameters");
1082 string parm = parms[1].ToUpper();
1083 if(parm.Equals("TRUE"))
1085 else if(parm.Equals("FALSE"))
1088 Console.WriteLine("Error: invalid parameter.");
1091 public void SetInternalVariable(string[] parms) {
1092 if(parms.Length < 2) {
1093 Console.WriteLine("Error: wrong number of parameters.");
1096 string parm = parms[1];
1097 StringBuilder ps = new StringBuilder();
1099 for(int i = 2; i < parms.Length; i++)
1100 ps.Append(parms[i]);
1102 internalVariables[parm] = ps.ToString();
1105 public void UnSetInternalVariable(string[] parms) {
1106 if(parms.Length != 2) {
1107 Console.WriteLine("Error: wrong number of parameters.");
1110 string parm = parms[1];
1113 internalVariables.Remove(parm);
1115 catch(Exception e) {
1116 Console.WriteLine("Error: internal variable does not exist: " +
1121 public void ShowInternalVariable(string[] parms) {
1122 string internalVariableValue = "";
1124 if(parms.Length != 2) {
1125 Console.WriteLine("Error: wrong number of parameters.");
1129 string parm = parms[1];
1131 if(GetInternalVariable(parm, out internalVariableValue) == true)
1132 Console.WriteLine("Internal Variable - Name: " +
1133 parm + " Value: " + internalVariableValue);
1136 public bool GetInternalVariable(string name, out string sValue) {
1138 bool valueReturned = false;
1141 if(internalVariables.ContainsKey(name) == true) {
1142 sValue = (string) internalVariables[name];
1143 valueReturned = true;
1146 Console.WriteLine("Error: internal variable does not exist.");
1149 catch(Exception e) {
1150 Console.WriteLine("Error: internal variable does not exist: "+
1153 return valueReturned;
1156 public void SetupExternalProvider(string[] parms) {
1157 if(parms.Length != 3) {
1158 Console.WriteLine("Error: Wrong number of parameters.");
1161 provider = "LOADEXTPROVIDER";
1162 providerAssembly = parms[1];
1163 providerConnectionClass = parms[2];
1166 public bool LoadExternalProvider() {
1169 bool success = false;
1171 // For example: for the MySQL provider in Mono.Data.MySql
1172 // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
1173 // \ConnectionString dbname=test
1175 // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
1181 Console.WriteLine("Loading external provider...");
1182 Console.Out.Flush();
1184 Assembly ps = Assembly.Load(providerAssembly);
1185 Type typ = ps.GetType(providerConnectionClass);
1186 conn = (IDbConnection) Activator.CreateInstance(typ);
1189 Console.WriteLine("External provider loaded.");
1190 Console.Out.Flush();
1192 catch(FileNotFoundException f) {
1193 msg = "Error: unable to load the assembly of the provider: " +
1196 Console.WriteLine(msg);
1198 catch(Exception e) {
1199 msg = "Error: unable to load the assembly of the provider: " +
1202 Console.WriteLine(msg);
1207 // used for outputting message, but if silent is set,
1209 public void OutputLine(string line) {
1214 // used for outputting the header columns of a result
1215 public void OutputHeader(string line) {
1216 if(showHeader == true)
1220 // OutputData() - used for outputting data
1221 // if an output filename is set, then the data will
1222 // go to a file; otherwise, it will go to the Console.
1223 public void OutputData(string line) {
1224 if(outputFilestream == null)
1225 Console.WriteLine(line);
1227 outputFilestream.WriteLine(line);
1230 // HandleCommand - handle SqlSharpCli commands entered
1231 public void HandleCommand(string entry) {
1234 parms = entry.Split(new char[1] {' '});
1235 string userCmd = parms[0].ToUpper();
1239 ChangeProvider(parms);
1241 case "\\CONNECTIONSTRING":
1242 ChangeConnectionString(entry);
1244 case "\\LOADEXTPROVIDER":
1245 SetupExternalProvider(parms);
1254 SetupSilentMode(parms);
1260 // Execute SQL Commands or Queries
1262 Console.WriteLine("Error: connection is not Open.");
1263 else if(conn.State == ConnectionState.Closed)
1264 Console.WriteLine("Error: connection is not Open.");
1267 Console.WriteLine("Error: SQL Buffer is empty.");
1269 buff = build.ToString();
1275 case "\\EXENONQUERY":
1277 Console.WriteLine("Error: connection is not Open.");
1278 else if(conn.State == ConnectionState.Closed)
1279 Console.WriteLine("Error: connection is not Open.");
1282 Console.WriteLine("Error: SQL Buffer is empty.");
1284 buff = build.ToString();
1285 ExecuteSqlNonQuery(buff);
1292 Console.WriteLine("Error: connection is not Open.");
1293 else if(conn.State == ConnectionState.Closed)
1294 Console.WriteLine("Error: connection is not Open.");
1297 Console.WriteLine("Error: SQL Buffer is empty.");
1299 buff = build.ToString();
1300 ExecuteSqlScalar(buff);
1306 // \exexml OUTPUT_FILENAME
1308 Console.WriteLine("Error: connection is not Open.");
1309 else if(conn.State == ConnectionState.Closed)
1310 Console.WriteLine("Error: connection is not Open.");
1313 Console.WriteLine("Error: SQL Buffer is empty.");
1315 buff = build.ToString();
1316 ExecuteSqlXml(buff, parms);
1322 SetupInputCommandsFile(parms);
1325 SetupOutputResultsFile(parms);
1328 // Load file into SQL buffer: \load FILENAME
1329 LoadBufferFromFile(parms);
1332 // Save SQL buffer to file: \save FILENAME
1333 SaveBufferToFile(parms);
1341 // show the defaults for provider and connection strings
1351 // reset (clear) the query buffer
1355 // sets internal variable
1357 SetInternalVariable(parms);
1360 // deletes internal variable
1362 UnSetInternalVariable(parms);
1365 ShowInternalVariable(parms);
1369 Console.WriteLine("SQL Buffer is empty.");
1371 Console.WriteLine("SQL Bufer:\n" + buff);
1373 case "\\USEPARAMETERS":
1374 SetUseParameters(parms);
1376 case "\\USESIMPLEREADER":
1377 SetUseSimpleReader(parms);
1381 Console.WriteLine("Error: Unknown user command.");
1386 public void DealWithArgs(string[] args) {
1387 for(int a = 0; a < args.Length; a++) {
1388 if(args[a].Substring(0,1).Equals("-")) {
1389 string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
1395 if(a + 1 >= args.Length)
1396 Console.WriteLine("Error: Missing FILENAME for -f switch");
1398 inputFilename = args[a + 1];
1399 inputFilestream = new StreamReader(inputFilename);
1403 if(a + 1 >= args.Length)
1404 Console.WriteLine("Error: Missing FILENAME for -o switch");
1406 outputFilename = args[a + 1];
1407 outputFilestream = new StreamWriter(outputFilename);
1411 Console.WriteLine("Error: Unknow switch: " + args[a]);
1418 public string ReadSqlSharpCommand() {
1421 if(inputFilestream == null) {
1422 Console.Write("\nSQL# ");
1423 entry = Console.ReadLine();
1427 entry = inputFilestream.ReadLine();
1429 Console.WriteLine("Executing SQL# Commands from file done.");
1432 catch(Exception e) {
1433 Console.WriteLine("Error: Reading command from file: " +
1436 Console.Write("\nSQL# ");
1437 entry = Console.ReadLine();
1442 public void Run(string[] args) {
1449 if(silent == false) {
1450 Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
1451 Console.WriteLine("for Mono.Data. See http://www.go-mono.com/ for more details.\n");
1457 while(entry.ToUpper().Equals("\\Q") == false &&
1458 entry.ToUpper().Equals("\\QUIT") == false) {
1460 while((entry = ReadSqlSharpCommand()) == "") {}
1463 if(entry.Substring(0,1).Equals("\\")) {
1464 HandleCommand(entry);
1466 else if(entry.IndexOf(";") >= 0) {
1467 // most likely the end of SQL Command or Query found
1470 Console.WriteLine("Error: connection is not Open.");
1471 else if(conn.State == ConnectionState.Closed)
1472 Console.WriteLine("Error: connection is not Open.");
1475 build = new StringBuilder();
1477 build.Append(entry);
1478 //build.Append("\n");
1479 buff = build.ToString();
1485 // most likely a part of a SQL Command or Query found
1486 // append this part of the SQL
1488 build = new StringBuilder();
1490 build.Append(entry + "\n");
1491 buff = build.ToString();
1495 if(outputFilestream != null)
1496 outputFilestream.Close();
1500 public enum BindVariableCharacter {
\r
1501 Colon, // ':' - named parameter - :name
\r
1502 At, // '@' - named parameter - @name
\r
1503 QuestionMark, // '?' - positioned parameter - ?
\r
1504 SquareBrackets // '[]' - delimited named parameter - [name]
\r
1507 public class ParametersBuilder {
\r
1509 private BindVariableCharacter bindCharSetting;
\r
1510 private char bindChar;
\r
1511 private IDataParameterCollection parms;
\r
1512 private string sql;
\r
1513 private IDbCommand cmd;
\r
1515 private void SetBindCharacter() {
\r
1516 switch(bindCharSetting) {
\r
1517 case BindVariableCharacter.Colon:
\r
1520 case BindVariableCharacter.At:
\r
1523 case BindVariableCharacter.SquareBrackets:
\r
1526 case BindVariableCharacter.QuestionMark:
\r
1532 public ParametersBuilder(IDbCommand command, BindVariableCharacter bindVarChar) {
\r
1534 sql = cmd.CommandText;
\r
1535 parms = cmd.Parameters;
\r
1536 bindCharSetting = bindVarChar;
\r
1537 SetBindCharacter();
\r
1540 public char ParameterMarkerCharacter {
\r
1546 public int ParseParameters() {
\r
1550 IDataParameterCollection parms = cmd.Parameters;
\r
1552 char[] chars = sql.ToCharArray();
\r
1553 bool bStringConstFound = false;
\r
1555 for(int i = 0; i < chars.Length; i++) {
\r
1556 if(chars[i] == '\'') {
\r
1557 if(bStringConstFound == true)
\r
1558 bStringConstFound = false;
\r
1560 bStringConstFound = true;
\r
1562 else if(chars[i] == bindChar &&
\r
1563 bStringConstFound == false) {
\r
1564 if(bindChar != '?') {
\r
1565 StringBuilder parm = new StringBuilder();
\r
1567 if(bindChar.Equals('[')) {
\r
1568 bool endingBracketFound = false;
\r
1569 while(i <= chars.Length) {
\r
1571 if(i == chars.Length)
\r
1572 ch = ' '; // a space
\r
1576 if(Char.IsLetterOrDigit(ch) || ch == ' ') {
\r
1579 else if (ch == ']') {
\r
1580 endingBracketFound = true;
\r
1581 string p = parm.ToString();
\r
1586 else throw new Exception("SQL Parser Error: Invalid character in parameter name");
\r
1590 if(endingBracketFound == false)
\r
1591 throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
\r
1594 while(i <= chars.Length) {
\r
1596 if(i == chars.Length)
\r
1597 ch = ' '; // a space
\r
1601 if(Char.IsLetterOrDigit(ch)) {
\r
1606 string p = parm.ToString();
\r
1617 // placeholder paramaeter for ?
\r
1618 string p = numParms.ToString();
\r
1627 public void AddParameter (string p) {
\r
1628 Console.WriteLine("Add Parameter: " + p);
\r
1629 if(parms.Contains(p) == false) {
\r
1630 IDataParameter prm = cmd.CreateParameter();
\r
1631 prm.ParameterName = p;
\r
1632 prm.Direction = ParameterDirection.Input;
\r
1633 prm.DbType = DbType.String; // default
\r
1634 prm.Value = ""; // default
\r
1635 cmd.Parameters.Add(prm);
\r
1640 public class SqlSharpDriver {
1641 public static void Main(string[] args) {
1642 SqlSharpCli sqlCommandLineEngine = new SqlSharpCli();
1643 sqlCommandLineEngine.Run(args);