2 // SqlSharpCli.cs - main driver for Mono SQL Query Command Line Interface
3 // found in mcs/tools/SqlSharp
5 // This program is included in Mono and is licenced under the GPL.
6 // http://www.fsf.org/licenses/gpl.html
8 // For more information about Mono,
9 // visit http://www.mono-project.com/
11 // To build SqlSharpCli.cs
12 // $ mcs /out:sqlsharp.exe SqlSharpCli.cs /r:System.Data.dll
15 // $ mono sqlsharp.exe
17 // To run batch commands and get the output, do something like:
18 // $ cat commands_example.txt | mono sqlsharp.exe -s > results.txt
21 // Daniel Morgan <monodanmorg@yahoo.com>
23 // (C)Copyright 2002-2004, 2008 Daniel Morgan
27 using System.Collections;
28 using System.Collections.Generic;
29 using System.Configuration;
31 using System.Data.Common;
32 using System.Data.OleDb;
33 using System.Data.SqlClient;
35 using System.Reflection;
36 using System.Runtime.Remoting;
39 namespace Mono.Data.SqlSharp {
41 public enum FileFormat {
49 // SQL Sharp - Command Line Interface
50 public class SqlSharpCli
53 private bool UseParameters = true;
54 private bool UseSimpleReader = false;
56 private IDbConnection conn = null;
58 private string provider = ""; // name of internal provider
59 // {OleDb,SqlClient,MySql,Odbc,Oracle,
60 // PostgreSql,SqlLite,Sybase,Tds} however, it
61 // can be set to LOADEXTPROVIDER to load an external provider
62 private string providerAssembly = "";
63 // filename of assembly
64 // for example: "Mono.Data.MySql"
65 private string providerConnectionClass = "";
67 // in the provider assembly that implements the IDbConnection
68 // interface. for example: "Mono.Data.MySql.MySqlConnection"
70 private StringBuilder build = null; // SQL string to build
71 private string buff = ""; // SQL string buffer
73 private string connectionString = "";
75 private string inputFilename = "";
76 private string outputFilename = "";
77 private StreamReader inputFilestream = null;
78 private StreamWriter outputFilestream = null;
80 private string factoryName = null;
81 private DbProviderFactory factory = null;
83 private FileFormat outputFileFormat = FileFormat.Html;
85 private bool silent = false;
86 private bool showHeader = true;
88 private Hashtable internalVariables = new Hashtable();
90 // DisplayResult - used to Read() display a result set
91 // called by DisplayData()
93 public bool DisplayResult (IDataReader reader, DataTable schemaTable)
95 StringBuilder column = null;
96 StringBuilder line = null;
97 StringBuilder hdrUnderline = null;
105 char spacingChar = ' '; // a space
106 char underlineChar = '='; // an equal sign
108 string dataType; // .NET Type
110 DataRow row; // schema row
112 line = new StringBuilder ();
113 hdrUnderline = new StringBuilder ();
117 for (c = 0; c < reader.FieldCount; c++) {
119 DataRow schemaRow = schemaTable.Rows [c];
120 string columnHeader = reader.GetName (c);
121 if (columnHeader.Equals (""))
122 columnHeader = "column";
123 if (columnHeader.Length > 32)
124 columnHeader = columnHeader.Substring (0,32);
127 columnSize = (int) schemaRow ["ColumnSize"];
128 theType = reader.GetFieldType (c);
129 dataType = theType.ToString ();
132 case "System.DateTime":
135 case "System.Boolean":
141 case "System.Single":
144 case "System.Double":
152 case "System.UInt32":
158 case "System.UInt64":
161 case "System.Decimal":
171 hdrLen = columnHeader.Length;
177 hdrLen = System.Math.Max (hdrLen, columnSize);
179 line.Append (columnHeader);
180 if (columnHeader.Length < hdrLen) {
181 spacing = hdrLen - columnHeader.Length;
182 line.Append (spacingChar, spacing);
184 hdrUnderline.Append (underlineChar, hdrLen);
187 hdrUnderline.Append (" ");
189 catch (Exception e) {
190 OutputLine ("Error: Unable to display header: " + e.Message);
194 OutputHeader (line.ToString ());
197 OutputHeader (hdrUnderline.ToString ());
205 while (reader.Read ()) {
208 line = new StringBuilder ();
209 for(c = 0; c < reader.FieldCount; c++) {
211 string dataValue = "";
212 column = new StringBuilder ();
215 row = schemaTable.Rows [c];
216 string colhdr = (string) reader.GetName (c);
217 if (colhdr.Equals (""))
219 if (colhdr.Length > 32)
220 colhdr = colhdr.Substring (0, 32);
222 columnSize = (int) row ["ColumnSize"];
223 theType = reader.GetFieldType (c);
224 dataType = theType.ToString ();
227 case "System.DateTime":
230 case "System.Boolean":
236 case "System.Single":
239 case "System.Double":
247 case "System.UInt32":
253 case "System.UInt64":
256 case "System.Decimal":
266 hdrLen = colhdr.Length;
272 columnSize = System.Math.Max (colhdr.Length, columnSize);
277 if (!reader.IsDBNull (c)) {
278 object o = reader.GetValue (c);
279 if (o.GetType ().ToString ().Equals ("System.Byte[]"))
280 dataValue = GetHexString ( (byte[]) o);
282 dataValue = o.ToString ();
284 dataLen = dataValue.Length;
291 dataValue = dataValue.Substring (0, 32);
295 if (dataValue.Equals(""))
298 columnSize = System.Math.Max (columnSize, dataLen);
300 if (dataLen < columnSize) {
305 case "System.UInt16":
307 case "System.UInt32":
309 case "System.UInt64":
310 case "System.Single":
311 case "System.Double":
312 case "System.Decimal":
313 outData = dataValue.PadLeft (columnSize);
316 outData = dataValue.PadRight (columnSize);
323 line.Append (outData);
326 OutputData (line.ToString ());
329 catch (Exception rr) {
330 OutputLine ("Error: Unable to read next row: " + rr.Message);
334 OutputLine ("\nRows retrieved: " + numRows.ToString ());
336 return true; // return true - success
339 public static string GetHexString (byte[] bytes)
343 if (bytes.Length > 0) {
344 StringBuilder sb = new StringBuilder ();
346 for (int z = 0; z < bytes.Length; z++)
347 sb.AppendFormat("{0:X2}", bytes [z]);
349 bvalue = "0x" + sb.ToString ();
355 public void OutputDataToHtmlFile (IDataReader rdr, DataTable dt)
357 StringBuilder strHtml = new StringBuilder ();
359 strHtml.Append ("<html> \n <head> <title>");
360 strHtml.Append ("Results");
361 strHtml.Append ("</title> </head>");
362 strHtml.Append ("<body>");
363 strHtml.Append ("<h1> Results </h1>");
364 strHtml.Append ("<table border=1>");
366 outputFilestream.WriteLine (strHtml.ToString ());
368 strHtml = new StringBuilder ();
370 strHtml.Append ("<tr>");
371 foreach (DataRow schemaRow in dt.Rows) {
372 strHtml.Append ("<td> <b>");
373 object dataObj = schemaRow ["ColumnName"];
374 string sColumnName = dataObj.ToString ();
375 strHtml.Append (sColumnName);
376 strHtml.Append ("</b> </td>");
378 strHtml.Append ("</tr>");
379 outputFilestream.WriteLine (strHtml.ToString ());
383 string dataValue = "";
385 while (rdr.Read ()) {
386 strHtml = new StringBuilder ();
388 strHtml.Append ("<tr>");
389 for (col = 0; col < rdr.FieldCount; col++) {
392 if (rdr.IsDBNull (col) == true)
395 object obj = rdr.GetValue (col);
396 dataValue = obj.ToString ();
398 strHtml.Append ("<td>");
399 strHtml.Append (dataValue);
400 strHtml.Append ("</td>");
402 strHtml.Append ("\t\t</tr>");
403 outputFilestream.WriteLine (strHtml.ToString ());
406 outputFilestream.WriteLine (" </table> </body> \n </html>");
410 // DisplayData - used to display any Result Sets
411 // from execution of SQL SELECT Query or Queries
412 // called by DisplayData.
413 // ExecuteSql() only calls this function
414 // for a Query, it does not get
416 public void DisplayData (IDataReader reader)
418 DataTable schemaTable = null;
422 // by Default, SqlDataReader has the
423 // first Result set if any
426 OutputLine ("Display the result set " + ResultSet);
428 schemaTable = reader.GetSchemaTable ();
430 if (reader.FieldCount > 0) {
431 // SQL Query (SELECT)
432 // RecordsAffected -1 and DataTable has a reference
433 OutputQueryResult (reader, schemaTable);
435 else if (reader.RecordsAffected >= 0) {
436 // SQL Command (INSERT, UPDATE, or DELETE)
437 // RecordsAffected >= 0
438 Console.WriteLine ("SQL Command Records Affected: " + reader.RecordsAffected);
441 // SQL Command (not INSERT, UPDATE, nor DELETE)
442 // RecordsAffected -1 and DataTable has a null reference
443 Console.WriteLine ("SQL Command Executed.");
446 // get next result set (if anymore is left)
447 } while (reader.NextResult ());
450 // display the result in a simple way
451 // new ADO.NET providers may have not certain
452 // things implemented yet, such as, TableSchema
454 public void DisplayDataSimple (IDataReader reader)
457 Console.WriteLine ("Reading Data using simple reader...");
458 while (reader.Read ()){
460 Console.WriteLine ("Row: " + row);
461 for (int col = 0; col < reader.FieldCount; col++) {
463 Console.WriteLine (" Field: " + co);
465 string dname = (string) reader.GetName (col);
468 if (dname.Equals (String.Empty))
470 Console.WriteLine (" Name: " + dname);
473 if (reader.IsDBNull (col))
476 dvalue = reader.GetValue (col).ToString ();
477 Console.WriteLine (" Value: " + dvalue);
480 Console.WriteLine ("\n" + row + " ROWS RETRIEVED\n");
483 public void OutputQueryResult (IDataReader dreader, DataTable dtable)
485 if (outputFilestream == null) {
486 DisplayResult (dreader, dtable);
489 switch (outputFileFormat) {
490 case FileFormat.Normal:
491 DisplayResult (dreader, dtable);
493 case FileFormat.Html:
494 OutputDataToHtmlFile (dreader, dtable);
497 Console.WriteLine ("Error: Output data file format not supported.");
503 public void BuildParameters (IDbCommand cmd)
505 if (UseParameters == true) {
507 ParametersBuilder parmsBuilder = new ParametersBuilder (cmd, BindVariableCharacter.Colon);
509 Console.WriteLine ("Get Parameters (if any)...");
510 parmsBuilder.ParseParameters ();
511 IList parms = (IList) cmd.Parameters;
513 Console.WriteLine ("Print each parm...");
514 for (int p = 0; p < parms.Count; p++) {
517 IDataParameter prm = (IDataParameter) parms[p];
518 theParmName = prm.ParameterName;
522 if (parmsBuilder.ParameterMarkerCharacter == '?') {
523 Console.Write ("Enter Parameter " +
526 inValue = Console.ReadLine();
530 found = GetInternalVariable (theParmName, out inValue);
535 Console.Write ("Enter Parameter " + (p + 1).ToString () +
536 ": " + theParmName + ": ");
537 inValue = Console.ReadLine ();
546 // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
547 public void ExecuteSql (string sql)
551 IDbCommand cmd = null;
552 IDataReader reader = null;
554 cmd = conn.CreateCommand();
556 // set command properties
557 cmd.CommandType = CommandType.Text;
558 cmd.CommandText = sql;
559 cmd.Connection = conn;
561 BuildParameters (cmd);
564 reader = cmd.ExecuteReader ();
566 if (UseSimpleReader == false)
567 DisplayData (reader);
569 DisplayDataSimple (reader);
574 catch (Exception e) {
575 msg = "Error: " + e.Message;
576 Console.WriteLine (msg);
584 // ExecuteSql - Execute the SQL Commands (no SELECTs)
585 public void ExecuteSqlNonQuery (string sql)
589 IDbCommand cmd = null;
590 int rowsAffected = -1;
592 cmd = conn.CreateCommand();
594 // set command properties
595 cmd.CommandType = CommandType.Text;
596 cmd.CommandText = sql;
597 cmd.Connection = conn;
599 BuildParameters(cmd);
602 rowsAffected = cmd.ExecuteNonQuery ();
604 Console.WriteLine ("Rows affected: " + rowsAffected);
607 msg = "Error: " + e.Message;
608 Console.WriteLine (msg);
615 public void ExecuteSqlScalar(string sql)
619 IDbCommand cmd = null;
620 string retrievedValue = "";
622 cmd = conn.CreateCommand ();
624 // set command properties
625 cmd.CommandType = CommandType.Text;
626 cmd.CommandText = sql;
627 cmd.Connection = conn;
629 BuildParameters(cmd);
632 retrievedValue = (string) cmd.ExecuteScalar ().ToString ();
633 Console.WriteLine ("Retrieved value: " + retrievedValue);
636 msg = "Error: " + e.Message;
637 Console.WriteLine (msg);
644 public void ExecuteSqlXml(string sql, string[] parms)
646 string filename = "";
648 if (parms.Length != 2) {
649 Console.WriteLine ("Error: wrong number of parameters");
653 filename = parms [1];
655 catch (Exception e) {
656 Console.WriteLine ("Error: Unable to setup output results file. " + e.Message);
661 IDbCommand cmd = null;
663 cmd = conn.CreateCommand ();
665 // set command properties
666 cmd.CommandType = CommandType.Text;
667 cmd.CommandText = sql;
668 cmd.Connection = conn;
670 BuildParameters (cmd);
671 DataSet dataSet = new DataSet ();
672 DbDataAdapter adapter = CreateNewDataAdapter (cmd, conn);
673 adapter.Fill (dataSet);
674 dataSet.WriteXml (filename);
675 OutputLine ("Data written to xml file: " + filename);
677 catch (Exception exexml) {
678 Console.WriteLine ("Error: Execute SQL XML Failure: " + exexml);
682 public DbDataAdapter CreateNewDataAdapter (IDbCommand command, IDbConnection connection)
684 DbDataAdapter adapter = null;
686 if (factory != null) {
687 adapter = factory.CreateDataAdapter();
688 DbCommand cmd = (DbCommand) command;
689 adapter.SelectCommand = cmd;
694 adapter = (DbDataAdapter) new OleDbDataAdapter ();
697 adapter = (DbDataAdapter) new SqlDataAdapter ();
699 case "LOADEXTPROVIDER":
700 adapter = CreateExternalDataAdapter (command, connection);
705 Console.WriteLine("Error: Data Adapter not found in provider.");
709 IDbDataAdapter dbAdapter = (IDbDataAdapter) adapter;
710 dbAdapter.SelectCommand = command;
715 public DbDataAdapter CreateExternalDataAdapter (IDbCommand command, IDbConnection connection)
717 DbDataAdapter adapter = null;
719 Assembly ass = Assembly.Load (providerAssembly);
720 Type [] types = ass.GetTypes ();
721 foreach (Type t in types) {
722 if (t.IsSubclassOf (typeof (System.Data.Common.DbDataAdapter))) {
723 if (t.Namespace.Equals (conType.Namespace))
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 ()
736 OutputLine (@"Type: \Q to quit");
737 OutputLine (@" \ConnectionString to set the ConnectionString");
738 OutputLine (@" \Provider to set the Provider:");
739 OutputLine (@" {OleDb,SqlClient,MySql,Odbc,DB2,");
740 OutputLine (@" Oracle,PostgreSql,Sqlite,Sybase,Tds)");
741 OutputLine (@" \Open to open the connection");
742 OutputLine (@" \Close to close the connection");
743 OutputLine (@" \e to execute SQL query (SELECT)");
744 OutputLine (@" \h to show help (all commands).");
745 OutputLine (@" \defaults to show default variables.");
749 // ShowHelp - show the help - command a user can enter
750 public void ShowHelp ()
752 Console.WriteLine ("");
753 Console.WriteLine (@"Type: \Q to quit");
754 Console.WriteLine (@" \ListP or \ListProviders to get factory providers");
755 Console.WriteLine (@" \CS or \ConnectionString to set the ConnectionString");
756 Console.WriteLine (@" \BCS to Build Connection String");
757 Console.WriteLine (@" \P or \Provider to set the Provider:");
758 Console.WriteLine (@" {OleDb,SqlClient,MySql,Odbc,");
759 Console.WriteLine (@" Oracle,PostgreSql,Sqlite,Sybase,Firebird}");
760 Console.WriteLine (@" \Open to open the connection");
761 Console.WriteLine (@" \Close to close the connection");
762 Console.WriteLine (@" \e to execute SQL query (SELECT)");
763 Console.WriteLine (@" \exenonquery to execute an SQL non query (not a SELECT).");
764 Console.WriteLine (@" \exescalar to execute SQL to get a single row and single column.");
765 Console.WriteLine (@" \exexml FILENAME to execute SQL and save output to XML file.");
766 if (!WaitForEnterKey ())
768 Console.WriteLine (@" \f FILENAME to read a batch of SQL# commands from file.");
769 Console.WriteLine (@" \o FILENAME to write result of commands executed to file.");
770 Console.WriteLine (@" \load FILENAME to load from file SQL commands into SQL buffer.");
771 Console.WriteLine (@" \save FILENAME to save SQL commands from SQL buffer to file.");
772 Console.WriteLine (@" \h to show help (all commands).");
773 Console.WriteLine (@" \defaults to show default variables, such as,");
774 Console.WriteLine (@" Provider and ConnectionString.");
775 Console.WriteLine (@" \s {TRUE, FALSE} to silent messages.");
776 Console.WriteLine (@" \r to reset or clear the query buffer.");
777 if (!WaitForEnterKey ())
779 Console.WriteLine (@" \set NAME VALUE to set an internal variable.");
780 Console.WriteLine (@" \unset NAME to remove an internal variable.");
781 Console.WriteLine (@" \variable NAME to display the value of an internal variable.");
782 Console.WriteLine (@" \loadextprovider ASSEMBLY CLASS to load the provider");
783 Console.WriteLine (@" use the complete name of its assembly and");
784 Console.WriteLine (@" its Connection class.");
785 Console.WriteLine (@" \print - show what's in the SQL buffer now.");
786 Console.WriteLine (@" \UseParameters (TRUE,FALSE) to use parameters when executing SQL.");
787 Console.WriteLine (@" \UseSimpleReader (TRUE,FALSE) to use simple reader when displaying results.");
788 Console.WriteLine ();
791 public bool WaitForEnterKey ()
793 Console.Write("Waiting... Press Enter key to continue. ");
794 string entry = Console.ReadLine();
795 if (entry.ToUpper() == "Q")
800 // ShowDefaults - show defaults for connection variables
801 public void ShowDefaults()
803 Console.WriteLine ();
804 if (provider.Equals (String.Empty) && factory == null)
805 Console.WriteLine ("Provider is not set.");
806 else if(factory != null) {
807 Console.WriteLine ("The default Provider is " + factoryName);
810 Console.WriteLine ("The default Provider is " + provider);
811 if (provider.Equals ("LOADEXTPROVIDER")) {
812 Console.WriteLine (" Assembly: " + providerAssembly);
813 Console.WriteLine (" Connection Class: " + providerConnectionClass);
816 Console.WriteLine ();
817 if (connectionString.Equals (""))
818 Console.WriteLine ("ConnectionString is not set.");
820 Console.WriteLine ("The default ConnectionString is: ");
821 Console.WriteLine (" \"" + connectionString + "\"");
822 Console.WriteLine ();
826 // OpenDataSource - open connection to the data source
827 public void OpenDataSource ()
831 if (factoryName.Equals(String.Empty) && provider.Equals(String.Empty)) {
832 Console.Error.WriteLine("Provider not set.");
837 Console.Error.WriteLine("Error: already connected.");
841 OutputLine ("Opening connection...");
844 if (!factoryName.Equals(String.Empty))
845 conn = factory.CreateConnection();
849 conn = new OleDbConnection ();
852 conn = new SqlConnection ();
854 case "LOADEXTPROVIDER":
855 if (LoadExternalProvider () == false)
859 Console.WriteLine ("Error: Bad argument or provider not supported.");
863 } catch (Exception e) {
864 msg = "Error: Unable to create Connection object because: " + e.Message;
865 Console.WriteLine (msg);
869 conn.ConnectionString = connectionString;
873 if (conn.State == ConnectionState.Open)
874 OutputLine ("Open was successfull.");
875 } catch (Exception e) {
876 msg = "Exception Caught Opening. " + e.Message;
877 Console.WriteLine (msg);
882 // CloseDataSource - close the connection to the data source
883 public void CloseDataSource () {
887 OutputLine ("Attempt to Close...");
890 OutputLine ("Close was successfull.");
891 } catch(Exception e) {
892 msg = "Exeception Caught Closing. " + e.Message;
893 Console.WriteLine (msg);
899 public bool IsOpen () {
901 if (conn.State.Equals(ConnectionState.Open))
906 // ChangeProvider - change the provider string variable
907 public void ChangeProvider (string[] parms) {
910 Console.Error.WriteLine("Error: already connected.");
916 connectionString = "";
919 if (parms.Length == 2) {
920 string parm = parms [1].ToUpper ();
924 case "SYSTEM.DATA.ORACLECLIENT":
925 factoryName = "SYSTEM.DATA.ORACLECLIENT";
928 case "MONO.DATA.SYBASECLIENT":
929 factoryName = "MONO.DATA.SYBASECLIENT";
933 case "MYSQL.DATA.MYSQLCLIENT":
934 factoryName = "MYSQL.DATA.MYSQLCLIENT";
937 case "MONO.DATA.SQLITE":
938 factoryName = "MONO.DATA.SQLITE";
941 case "SYSTEM.DATA.ODBC":
942 factoryName = "SYSTEM.DATA.ODBC";
945 case "SYSTEM.DATA.OLEDB":
946 factoryName = "SYSTEM.DATA.OLEDB";
949 case "FIREBIRDSQL.DATA.FIREBIRD":
950 factoryName = "FIREBIRDSQL.DATA.FIREBIRD";
955 factoryName = "NPGSQL.DATA";
958 case "SYSTEM.DATA.SQLCLIENT":
959 factoryName = "SYSTEM.DATA.SQLCLIENT";
962 Console.WriteLine ("Error: " + "Bad argument or Provider not supported.");
966 factory = DbProviderFactories.GetFactory(factoryName);
967 } catch(ConfigurationException) {
968 Console.Error.WriteLine("*** Error: Unable to load provider factory: " +
970 "*** Check your machine.config to see if the provider is " +
971 "listed under section system.data and DbProviderFactories " +
972 "and that your provider assembly is in the GAC. Your provider " +
973 "may not support ADO.NET 2.0 factory and other features yet.");
975 ChangeProviderBackwardsCompat (parms);
978 OutputLine ("The default Provider is " + factoryName);
981 Console.WriteLine ("Error: provider only has one parameter.");
984 public void ChangeProviderBackwardsCompat (string[] parms)
986 Console.Error.WriteLine ("*** Setting provider using Backwards Compatibility mode.");
990 if (parms.Length == 2) {
991 string parm = parms [1].ToUpper ();
994 extp = new string[3] {
996 @"System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
997 "System.Data.OracleClient.OracleConnection"};
998 SetupExternalProvider (extp);
999 UseParameters = false;
1000 UseSimpleReader = false;
1003 extp = new string[3] {
1004 "\\loadextprovider",
1005 @"Mono.Data.TdsClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1006 "Mono.Data.TdsClient.TdsConnection"};
1007 SetupExternalProvider (extp);
1008 UseParameters = false;
1009 UseSimpleReader = false;
1012 extp = new string[3] {
1013 "\\loadextprovider",
1014 @"Mono.Data.SybaseClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1015 "Mono.Data.SybaseClient.SybaseConnection"};
1016 SetupExternalProvider (extp);
1017 UseParameters = false;
1018 UseSimpleReader = false;
1021 extp = new string[3] {
1022 "\\loadextprovider",
1023 @"ByteFX.Data, Version=0.7.6.1, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1024 "ByteFX.Data.MySqlClient.MySqlConnection"};
1025 SetupExternalProvider (extp);
1026 UseParameters = false;
1027 UseSimpleReader = false;
1031 extp = new string[3] {
1032 "\\loadextprovider",
1033 @"MySql.Data, Version=1.0.7.30073, Culture=neutral, PublicKeyToken=8e323390df8d9ed4",
1034 "MySql.Data.MySqlClient.MySqlConnection"};
1035 SetupExternalProvider (extp);
1036 UseParameters = false;
1037 UseSimpleReader = false;
1040 extp = new string[3] {
1041 "\\loadextprovider",
1042 @"Mono.Data.SqliteClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1043 "Mono.Data.SqliteClient.SqliteConnection"};
1044 SetupExternalProvider (extp);
1045 UseParameters = false;
1046 UseSimpleReader = true;
1049 UseParameters = false;
1050 UseSimpleReader = false;
1053 case "ODBC": // for MS NET 1.1 and above
1054 extp = new string[3] {
1055 "\\loadextprovider",
1056 @"System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
1057 "System.Data.Odbc.OdbcConnection"};
1058 SetupExternalProvider (extp);
1059 UseParameters = false;
1060 UseSimpleReader = false;
1062 case "MSODBC": // for MS NET 1.0
1063 extp = new string[3] {
1064 "\\loadextprovider",
1065 @"Microsoft.Data.Odbc, Culture=neutral, PublicKeyToken=b77a5c561934e089, Version=1.0.3300.0",
1066 "Microsoft.Data.Odbc.OdbcConnection"};
1067 SetupExternalProvider (extp);
1068 UseParameters = false;
1069 UseSimpleReader = false;
1072 UseParameters = false;
1073 UseSimpleReader = true;
1077 extp = new string[3] {
1078 "\\loadextprovider",
1079 @"FirebirdSql.Data.Firebird, Version=1.7.1.0, Culture=neutral, PublicKeyToken=0706f5520aae4ff4",
1080 "FirebirdSql.Data.Firebird.FbConnection"};
1081 SetupExternalProvider (extp);
1082 UseParameters = false;
1083 UseSimpleReader = false;
1087 extp = new string[3] {
1088 "\\loadextprovider",
1089 @"Npgsql, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7",
1090 "Npgsql.NpgsqlConnection"};
1091 SetupExternalProvider (extp);
1092 UseParameters = false;
1093 UseSimpleReader = false;
1096 Console.WriteLine ("Error: " + "Bad argument or Provider not supported.");
1099 OutputLine ("The default Provider is " + provider);
1100 if (provider.Equals ("LOADEXTPROVIDER")) {
1101 OutputLine (" Assembly: " +
1103 OutputLine (" Connection Class: " +
1104 providerConnectionClass);
1108 Console.WriteLine ("Error: provider only has one parameter.");
1111 // ChangeConnectionString - change the connection string variable
1112 public void ChangeConnectionString (string[] parms, string entry)
1114 if (parms.Length >= 2)
1115 connectionString = entry.Substring (parms[0].Length, entry.Length - (parms[0].Length + 1));
1117 connectionString = "";
1120 public void SetupOutputResultsFile (string[] parms) {
1121 if (parms.Length != 2) {
1122 Console.WriteLine ("Error: wrong number of parameters");
1126 outputFilestream = new StreamWriter (parms[1]);
1128 catch (Exception e) {
1129 Console.WriteLine ("Error: Unable to setup output results file. " + e.Message);
1134 public void SetupInputCommandsFile (string[] parms)
1136 if (parms.Length != 2) {
1137 Console.WriteLine ("Error: wrong number of parameters");
1141 inputFilestream = new StreamReader (parms[1]);
1143 catch (Exception e) {
1144 Console.WriteLine ("Error: Unable to setup input commmands file. " + e.Message);
1149 public void LoadBufferFromFile (string[] parms)
1151 if (parms.Length != 2) {
1152 Console.WriteLine ("Error: wrong number of parameters");
1155 string inFilename = parms[1];
1157 StreamReader sr = new StreamReader (inFilename);
1158 StringBuilder buffer = new StringBuilder ();
1161 while ((NextLine = sr.ReadLine ()) != null) {
1162 buffer.Append (NextLine);
1163 buffer.Append ("\n");
1166 buff = buffer.ToString ();
1168 build = new StringBuilder ();
1171 catch (Exception e) {
1172 Console.WriteLine ("Error: Unable to read file into SQL Buffer. " + e.Message);
1176 public void SaveBufferToFile(string[] parms)
1178 if (parms.Length != 2) {
1179 Console.WriteLine ("Error: wrong number of parameters");
1182 string outFilename = parms[1];
1184 StreamWriter sw = new StreamWriter (outFilename);
1185 sw.WriteLine (buff);
1188 catch (Exception e) {
1189 Console.WriteLine ("Error: Could not save SQL Buffer to file." + e.Message);
1193 public void SetUseParameters (string[] parms)
1195 if (parms.Length != 2) {
1196 Console.WriteLine ("Error: wrong number of parameters");
1199 string parm = parms[1].ToUpper ();
1200 if (parm.Equals ("TRUE"))
1201 UseParameters = true;
1202 else if (parm.Equals ("FALSE"))
1203 UseParameters = false;
1205 Console.WriteLine ("Error: invalid parameter.");
1209 public void SetUseSimpleReader (string[] parms)
1211 if (parms.Length != 2) {
1212 Console.WriteLine ("Error: wrong number of parameters");
1215 string parm = parms[1].ToUpper ();
1216 if (parm.Equals ("TRUE"))
1217 UseSimpleReader = true;
1218 else if (parm.Equals ("FALSE"))
1219 UseSimpleReader = false;
1221 Console.WriteLine ("Error: invalid parameter.");
1224 public void SetupSilentMode (string[] parms)
1226 if (parms.Length != 2) {
1227 Console.WriteLine ("Error: wrong number of parameters");
1230 string parm = parms[1].ToUpper ();
1231 if (parm.Equals ("TRUE"))
1233 else if (parm.Equals ("FALSE"))
1236 Console.WriteLine ("Error: invalid parameter.");
1239 public void SetInternalVariable(string[] parms)
1241 if (parms.Length < 2) {
1242 Console.WriteLine ("Error: wrong number of parameters.");
1245 string parm = parms[1];
1246 StringBuilder ps = new StringBuilder ();
1248 for (int i = 2; i < parms.Length; i++)
1249 ps.Append (parms[i]);
1251 internalVariables[parm] = ps.ToString ();
1254 public void UnSetInternalVariable(string[] parms)
1256 if (parms.Length != 2) {
1257 Console.WriteLine ("Error: wrong number of parameters.");
1260 string parm = parms[1];
1263 internalVariables.Remove (parm);
1264 } catch(Exception e) {
1265 Console.WriteLine ("Error: internal variable does not exist: " + e.Message);
1269 public void ShowInternalVariable(string[] parms)
1271 string internalVariableValue = "";
1273 if (parms.Length != 2) {
1274 Console.WriteLine ("Error: wrong number of parameters.");
1278 string parm = parms[1];
1280 if (GetInternalVariable(parm, out internalVariableValue) == true)
1281 Console.WriteLine ("Internal Variable - Name: " +
1282 parm + " Value: " + internalVariableValue);
1285 public bool GetInternalVariable(string name, out string sValue)
1288 bool valueReturned = false;
1291 if (internalVariables.ContainsKey (name) == true) {
1292 sValue = (string) internalVariables[name];
1293 valueReturned = true;
1296 Console.WriteLine ("Error: internal variable does not exist.");
1299 catch(Exception e) {
1300 Console.WriteLine ("Error: internal variable does not exist: "+ e.Message);
1302 return valueReturned;
1305 public void SetupExternalProvider(string[] parms)
1307 if (parms.Length != 3) {
1308 Console.WriteLine ("Error: Wrong number of parameters.");
1311 provider = "LOADEXTPROVIDER";
1312 providerAssembly = parms[1];
1313 providerConnectionClass = parms[2];
1316 public bool LoadExternalProvider ()
1320 bool success = false;
1322 // For example: for the MySQL provider in Mono.Data.MySql
1323 // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
1324 // \ConnectionString dbname=test
1326 // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
1332 OutputLine ("Loading external provider...");
1334 Assembly ps = Assembly.Load (providerAssembly);
1335 conType = ps.GetType (providerConnectionClass);
1336 conn = (IDbConnection) Activator.CreateInstance (conType);
1339 OutputLine ("External provider loaded.");
1340 UseParameters = false;
1341 } catch(FileNotFoundException f) {
1342 msg = "Error: unable to load the assembly of the provider: " + providerAssembly + " : " + f.Message;
1343 Console.WriteLine(msg);
1345 catch(Exception e) {
1346 msg = "Error: unable to load the assembly of the provider: " + providerAssembly + " : " + e.Message;
1347 Console.WriteLine(msg);
1352 // used for outputting message, but if silent is set,
1354 public void OutputLine (string line)
1356 if (silent == false)
1360 // used for outputting the header columns of a result
1361 public void OutputHeader (string line)
1363 if (showHeader == true)
1367 // OutputData() - used for outputting data
1368 // if an output filename is set, then the data will
1369 // go to a file; otherwise, it will go to the Console.
1370 public void OutputData(string line)
1372 if (outputFilestream == null)
1373 Console.WriteLine (line);
1375 outputFilestream.WriteLine (line);
1378 // HandleCommand - handle SqlSharpCli commands entered
1379 public void HandleCommand (string entry)
1383 parms = entry.Split (new char[1] {' '});
1384 string userCmd = parms[0].ToUpper ();
1387 case "\\LISTPROVIDERS":
1393 ChangeProvider (parms);
1395 case "\\CONNECTIONSTRING":
1397 ChangeConnectionString (parms, entry);
1399 case "\\LOADEXTPROVIDER":
1400 SetupExternalProvider (parms);
1409 SetupSilentMode (parms);
1415 // Execute SQL Commands or Queries
1417 Console.WriteLine ("Error: connection is not Open.");
1418 else if (conn.State == ConnectionState.Closed)
1419 Console.WriteLine ("Error: connection is not Open.");
1422 Console.WriteLine ("Error: SQL Buffer is empty.");
1424 buff = build.ToString ();
1430 case "\\EXENONQUERY":
1432 Console.WriteLine ("Error: connection is not Open.");
1433 else if (conn.State == ConnectionState.Closed)
1434 Console.WriteLine ("Error: connection is not Open.");
1437 Console.WriteLine ("Error: SQL Buffer is empty.");
1439 buff = build.ToString ();
1440 ExecuteSqlNonQuery (buff);
1447 Console.WriteLine ("Error: connection is not Open.");
1448 else if (conn.State == ConnectionState.Closed)
1449 Console.WriteLine ("Error: connection is not Open.");
1452 Console.WriteLine ("Error: SQL Buffer is empty.");
1454 buff = build.ToString ();
1455 ExecuteSqlScalar (buff);
1461 // \exexml OUTPUT_FILENAME
1463 Console.WriteLine ("Error: connection is not Open.");
1464 else if (conn.State == ConnectionState.Closed)
1465 Console.WriteLine ("Error: connection is not Open.");
1468 Console.WriteLine ("Error: SQL Buffer is empty.");
1470 buff = build.ToString ();
1471 ExecuteSqlXml (buff, parms);
1477 SetupInputCommandsFile (parms);
1480 SetupOutputResultsFile (parms);
1483 // Load file into SQL buffer: \load FILENAME
1484 LoadBufferFromFile (parms);
1487 // Save SQL buffer to file: \save FILENAME
1488 SaveBufferToFile (parms);
1496 // show the defaults for provider and connection strings
1500 BuildConnectionString ();
1509 // reset (clear) the query buffer
1513 // sets internal variable
1515 SetInternalVariable (parms);
1518 // deletes internal variable
1520 UnSetInternalVariable (parms);
1523 ShowInternalVariable (parms);
1527 Console.WriteLine ("SQL Buffer is empty.");
1529 Console.WriteLine ("SQL Bufer:\n" + buff);
1531 case "\\USEPARAMETERS":
1532 SetUseParameters (parms);
1534 case "\\USESIMPLEREADER":
1535 SetUseSimpleReader (parms);
1539 Console.WriteLine ("Error: Unknown user command.");
1544 public void ListProviders()
1546 DataTable table = DbProviderFactories.GetFactoryClasses();
1547 Console.WriteLine("List of Providers:");
1548 for (int r = 0; r < table.Rows.Count; r++)
1550 Console.WriteLine("---------------------");
1551 Console.WriteLine(" Name: " + table.Rows[r][0].ToString());
1552 Console.WriteLine(" Description: " + table.Rows[r][1].ToString());
1553 Console.WriteLine(" InvariantName: " + table.Rows[r][2].ToString());
1554 Console.WriteLine(" AssemblyQualifiedName: " + table.Rows[r][3].ToString());
1556 Console.WriteLine("---------------------");
1557 Console.WriteLine("Providers found: " + table.Rows.Count.ToString());
1560 public void DealWithArgs(string[] args)
1562 for (int a = 0; a < args.Length; a++) {
1563 if (args[a].Substring (0,1).Equals ("-")) {
1564 string arg = args [a].ToUpper ().Substring (1, args [a].Length - 1);
1570 if (a + 1 >= args.Length)
1571 Console.WriteLine ("Error: Missing FILENAME for -f switch");
1573 inputFilename = args [a + 1];
1574 inputFilestream = new StreamReader (inputFilename);
1578 if (a + 1 >= args.Length)
1579 Console.WriteLine ("Error: Missing FILENAME for -o switch");
1581 outputFilename = args [a + 1];
1582 outputFilestream = new StreamWriter (outputFilename);
1586 Console.WriteLine ("Error: Unknow switch: " + args [a]);
1593 public string GetPasswordFromConsole ()
1595 StringBuilder pb = new StringBuilder ();
1596 Console.Write ("\nPassword: ");
1597 ConsoleKeyInfo cki = Console.ReadKey (true);
1599 while (cki.Key != ConsoleKey.Enter) {
1600 if (cki.Key == ConsoleKey.Backspace) {
1601 if (pb.Length > 0) {
1602 pb.Remove (pb.Length - 1, 1);
1603 Console.Write ("\b");
1604 Console.Write (" ");
1605 Console.Write ("\b");
1608 pb.Append (cki.KeyChar);
1609 Console.Write ("*");
1611 cki = Console.ReadKey (true);
1614 Console.WriteLine ();
1615 return pb.ToString ();
1618 public string ReadSqlSharpCommand()
1622 if (inputFilestream == null) {
1623 if (silent == false)
1624 Console.Error.Write ("\nSQL# ");
1625 entry = Console.ReadLine ();
1629 entry = inputFilestream.ReadLine ();
1630 if (entry == null) {
1631 OutputLine ("Executing SQL# Commands from file done.");
1634 catch (Exception e) {
1635 Console.WriteLine ("Error: Reading command from file: " + e.Message);
1637 if (silent == false)
1638 Console.Error.Write ("\nSQL# ");
1639 entry = Console.ReadLine ();
1644 public string ReadConnectionOption(string option, string defaultVal)
1646 Console.Error.Write ("\nConnectionString Option: {0} [{1}] SQL# ", option, defaultVal);
1647 return Console.ReadLine ();
1650 public void BuildConnectionString ()
1652 if (factory == null) {
1653 Console.WriteLine("Provider is not set.");
1657 DbConnectionStringBuilder sb = factory.CreateConnectionStringBuilder ();
1658 if (!connectionString.Equals(String.Empty))
1659 sb.ConnectionString = connectionString;
1662 foreach (string key in sb.Keys) {
1663 if (key.ToUpper().Equals("PASSWORD") || key.ToUpper().Equals("PWD")) {
1664 string pwd = GetPasswordFromConsole ();
1667 } catch(Exception e) {
1668 Console.Error.WriteLine("Error: unable to set key. Reason: " + e.Message);
1672 string defaultVal = sb[key].ToString ();
1674 val = ReadConnectionOption (key, defaultVal);
1675 if (val.ToUpper ().Equals ("\\STOP"))
1680 } catch(Exception e) {
1681 Console.Error.WriteLine("Error: unable to set key. Reason: " + e.Message);
1689 Console.Error.WriteLine("Warning: your provider does not subclass DbConnectionStringBuilder fully.");
1693 connectionString = sb.ConnectionString;
1694 Console.WriteLine("ConnectionString is set.");
1697 public void Run (string[] args)
1699 DealWithArgs (args);
1704 if (silent == false) {
1705 Console.WriteLine ("Welcome to SQL#. The interactive SQL command-line client ");
1706 Console.WriteLine ("for Mono.Data. See http://www.mono-project.com/ for more details.\n");
1712 while (entry.ToUpper ().Equals ("\\Q") == false &&
1713 entry.ToUpper ().Equals ("\\QUIT") == false) {
1715 while ((entry = ReadSqlSharpCommand ()) == "") {}
1718 if (entry.Substring(0,1).Equals ("\\")) {
1719 HandleCommand (entry);
1721 else if (entry.IndexOf(";") >= 0) {
1722 // most likely the end of SQL Command or Query found
1725 Console.WriteLine ("Error: connection is not Open.");
1726 else if (conn.State == ConnectionState.Closed)
1727 Console.WriteLine ("Error: connection is not Open.");
1729 if (build == null) {
1730 build = new StringBuilder ();
1732 build.Append (entry);
1733 //build.Append ("\n");
1734 buff = build.ToString ();
1740 // most likely a part of a SQL Command or Query found
1741 // append this part of the SQL
1742 if (build == null) {
1743 build = new StringBuilder ();
1745 build.Append (entry + "\n");
1746 buff = build.ToString ();
1750 if (outputFilestream != null)
1751 outputFilestream.Close ();
1755 public enum BindVariableCharacter {
1756 Colon, // ':' - named parameter - :name
1757 At, // '@' - named parameter - @name
1758 QuestionMark, // '?' - positioned parameter - ?
1759 SquareBrackets // '[]' - delimited named parameter - [name]
1762 public class ParametersBuilder
1764 private BindVariableCharacter bindCharSetting;
1765 private char bindChar;
1766 private IDataParameterCollection parms;
1768 private IDbCommand cmd;
1770 private void SetBindCharacter ()
1772 switch(bindCharSetting) {
1773 case BindVariableCharacter.Colon:
1776 case BindVariableCharacter.At:
1779 case BindVariableCharacter.SquareBrackets:
1782 case BindVariableCharacter.QuestionMark:
1788 public ParametersBuilder (IDbCommand command, BindVariableCharacter bindVarChar)
1791 sql = cmd.CommandText;
1792 parms = cmd.Parameters;
1793 bindCharSetting = bindVarChar;
1797 public char ParameterMarkerCharacter {
1803 public int ParseParameters ()
1807 char[] chars = sql.ToCharArray ();
1808 bool bStringConstFound = false;
1810 for (int i = 0; i < chars.Length; i++) {
1811 if (chars[i] == '\'') {
1812 if (bStringConstFound == true)
1813 bStringConstFound = false;
1815 bStringConstFound = true;
1817 else if (chars[i] == bindChar &&
1818 bStringConstFound == false) {
1819 if (bindChar != '?') {
1820 StringBuilder parm = new StringBuilder ();
1822 if (bindChar.Equals ('[')) {
1823 bool endingBracketFound = false;
1824 while (i <= chars.Length) {
1826 if (i == chars.Length)
1827 ch = ' '; // a space
1831 if (Char.IsLetterOrDigit (ch) || ch == ' ') {
1834 else if (ch == ']') {
1835 endingBracketFound = true;
1836 string p = parm.ToString ();
1841 else throw new Exception("SQL Parser Error: Invalid character in parameter name");
1845 if (endingBracketFound == false)
1846 throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
1849 while (i <= chars.Length) {
1851 if (i == chars.Length)
1852 ch = ' '; // a space
1856 if (Char.IsLetterOrDigit(ch)) {
1861 string p = parm.ToString ();
1872 // placeholder paramaeter for ?
1873 string p = numParms.ToString ();
1882 public void AddParameter (string p)
1884 Console.WriteLine ("Add Parameter: " + p);
1885 if (parms.Contains (p) == false) {
1886 IDataParameter prm = cmd.CreateParameter ();
1887 prm.ParameterName = p;
1888 prm.Direction = ParameterDirection.Input;
1889 prm.DbType = DbType.String; // default
1890 prm.Value = ""; // default
1891 cmd.Parameters.Add(prm);
1897 public class SqlSharpDriver
1899 public static void Main (string[] args)
1901 SqlSharpCli sqlCommandLineEngine = new SqlSharpCli ();
1902 sqlCommandLineEngine.Run (args);