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
= "";
921 if (parms
.Length
== 2) {
922 string parm
= parms
[1].ToUpper ();
926 case "SYSTEM.DATA.ORACLECLIENT":
927 factoryName
= "SYSTEM.DATA.ORACLECLIENT";
930 case "MONO.DATA.SYBASECLIENT":
931 factoryName
= "MONO.DATA.SYBASECLIENT";
935 case "MYSQL.DATA.MYSQLCLIENT":
936 factoryName
= "MYSQL.DATA.MYSQLCLIENT";
939 case "MONO.DATA.SQLITE":
940 factoryName
= "MONO.DATA.SQLITE";
943 case "SYSTEM.DATA.ODBC":
944 factoryName
= "SYSTEM.DATA.ODBC";
947 case "SYSTEM.DATA.OLEDB":
948 factoryName
= "SYSTEM.DATA.OLEDB";
951 case "FIREBIRDSQL.DATA.FIREBIRD":
952 factoryName
= "FIREBIRDSQL.DATA.FIREBIRD";
957 factoryName
= "NPGSQL.DATA";
960 case "SYSTEM.DATA.SQLCLIENT":
961 factoryName
= "SYSTEM.DATA.SQLCLIENT";
964 Console
.WriteLine ("Error: " + "Bad argument or Provider not supported.");
968 factory
= DbProviderFactories
.GetFactory(factoryName
);
969 } catch(ConfigurationException e
) {
970 Console
.Error
.WriteLine("*** Error: Unable to load provider factory: " +
972 "*** Check your machine.config to see if the provider is " +
973 "listed under section system.data and DbProviderFactories " +
974 "and that your provider assembly is in the GAC. Your provider " +
975 "may not support ADO.NET 2.0 factory and other features yet.");
977 ChangeProviderBackwardsCompat (parms
);
980 OutputLine ("The default Provider is " + factoryName
);
983 Console
.WriteLine ("Error: provider only has one parameter.");
986 public void ChangeProviderBackwardsCompat (string[] parms
)
988 Console
.Error
.WriteLine ("*** Setting provider using Backwards Compatibility mode.");
992 if (parms
.Length
== 2) {
993 string parm
= parms
[1].ToUpper ();
996 extp
= new string[3] {
998 @"System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
999 "System.Data.OracleClient.OracleConnection"};
1000 SetupExternalProvider (extp
);
1001 UseParameters
= false;
1002 UseSimpleReader
= false;
1005 extp
= new string[3] {
1006 "\\loadextprovider",
1007 @"Mono.Data.TdsClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1008 "Mono.Data.TdsClient.TdsConnection"};
1009 SetupExternalProvider (extp
);
1010 UseParameters
= false;
1011 UseSimpleReader
= false;
1014 extp
= new string[3] {
1015 "\\loadextprovider",
1016 @"Mono.Data.SybaseClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1017 "Mono.Data.SybaseClient.SybaseConnection"};
1018 SetupExternalProvider (extp
);
1019 UseParameters
= false;
1020 UseSimpleReader
= false;
1023 extp
= new string[3] {
1024 "\\loadextprovider",
1025 @"ByteFX.Data, Version=0.7.6.1, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1026 "ByteFX.Data.MySqlClient.MySqlConnection"};
1027 SetupExternalProvider (extp
);
1028 UseParameters
= false;
1029 UseSimpleReader
= false;
1033 extp
= new string[3] {
1034 "\\loadextprovider",
1035 @"MySql.Data, Version=1.0.7.30073, Culture=neutral, PublicKeyToken=8e323390df8d9ed4",
1036 "MySql.Data.MySqlClient.MySqlConnection"};
1037 SetupExternalProvider (extp
);
1038 UseParameters
= false;
1039 UseSimpleReader
= false;
1042 extp
= new string[3] {
1043 "\\loadextprovider",
1044 @"Mono.Data.SqliteClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
1045 "Mono.Data.SqliteClient.SqliteConnection"};
1046 SetupExternalProvider (extp
);
1047 UseParameters
= false;
1048 UseSimpleReader
= true;
1051 UseParameters
= false;
1052 UseSimpleReader
= false;
1055 case "ODBC": // for MS NET 1.1 and above
1056 extp
= new string[3] {
1057 "\\loadextprovider",
1058 @"System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
1059 "System.Data.Odbc.OdbcConnection"};
1060 SetupExternalProvider (extp
);
1061 UseParameters
= false;
1062 UseSimpleReader
= false;
1064 case "MSODBC": // for MS NET 1.0
1065 extp
= new string[3] {
1066 "\\loadextprovider",
1067 @"Microsoft.Data.Odbc, Culture=neutral, PublicKeyToken=b77a5c561934e089, Version=1.0.3300.0",
1068 "Microsoft.Data.Odbc.OdbcConnection"};
1069 SetupExternalProvider (extp
);
1070 UseParameters
= false;
1071 UseSimpleReader
= false;
1074 UseParameters
= false;
1075 UseSimpleReader
= true;
1079 extp
= new string[3] {
1080 "\\loadextprovider",
1081 @"FirebirdSql.Data.Firebird, Version=1.7.1.0, Culture=neutral, PublicKeyToken=0706f5520aae4ff4",
1082 "FirebirdSql.Data.Firebird.FbConnection"};
1083 SetupExternalProvider (extp
);
1084 UseParameters
= false;
1085 UseSimpleReader
= false;
1089 extp
= new string[3] {
1090 "\\loadextprovider",
1091 @"Npgsql, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7",
1092 "Npgsql.NpgsqlConnection"};
1093 SetupExternalProvider (extp
);
1094 UseParameters
= false;
1095 UseSimpleReader
= false;
1098 Console
.WriteLine ("Error: " + "Bad argument or Provider not supported.");
1101 OutputLine ("The default Provider is " + provider
);
1102 if (provider
.Equals ("LOADEXTPROVIDER")) {
1103 OutputLine (" Assembly: " +
1105 OutputLine (" Connection Class: " +
1106 providerConnectionClass
);
1110 Console
.WriteLine ("Error: provider only has one parameter.");
1113 // ChangeConnectionString - change the connection string variable
1114 public void ChangeConnectionString (string[] parms
, string entry
)
1116 if (parms
.Length
>= 2)
1117 connectionString
= entry
.Substring (parms
[0].Length
, entry
.Length
- (parms
[0].Length
+ 1));
1119 connectionString
= "";
1122 public void SetupOutputResultsFile (string[] parms
) {
1123 if (parms
.Length
!= 2) {
1124 Console
.WriteLine ("Error: wrong number of parameters");
1128 outputFilestream
= new StreamWriter (parms
[1]);
1130 catch (Exception e
) {
1131 Console
.WriteLine ("Error: Unable to setup output results file. " + e
.Message
);
1136 public void SetupInputCommandsFile (string[] parms
)
1138 if (parms
.Length
!= 2) {
1139 Console
.WriteLine ("Error: wrong number of parameters");
1143 inputFilestream
= new StreamReader (parms
[1]);
1145 catch (Exception e
) {
1146 Console
.WriteLine ("Error: Unable to setup input commmands file. " + e
.Message
);
1151 public void LoadBufferFromFile (string[] parms
)
1153 if (parms
.Length
!= 2) {
1154 Console
.WriteLine ("Error: wrong number of parameters");
1157 string inFilename
= parms
[1];
1159 StreamReader sr
= new StreamReader (inFilename
);
1160 StringBuilder buffer
= new StringBuilder ();
1163 while ((NextLine
= sr
.ReadLine ()) != null) {
1164 buffer
.Append (NextLine
);
1165 buffer
.Append ("\n");
1168 buff
= buffer
.ToString ();
1170 build
= new StringBuilder ();
1173 catch (Exception e
) {
1174 Console
.WriteLine ("Error: Unable to read file into SQL Buffer. " + e
.Message
);
1178 public void SaveBufferToFile(string[] parms
)
1180 if (parms
.Length
!= 2) {
1181 Console
.WriteLine ("Error: wrong number of parameters");
1184 string outFilename
= parms
[1];
1186 StreamWriter sw
= new StreamWriter (outFilename
);
1187 sw
.WriteLine (buff
);
1190 catch (Exception e
) {
1191 Console
.WriteLine ("Error: Could not save SQL Buffer to file." + e
.Message
);
1195 public void SetUseParameters (string[] parms
)
1197 if (parms
.Length
!= 2) {
1198 Console
.WriteLine ("Error: wrong number of parameters");
1201 string parm
= parms
[1].ToUpper ();
1202 if (parm
.Equals ("TRUE"))
1203 UseParameters
= true;
1204 else if (parm
.Equals ("FALSE"))
1205 UseParameters
= false;
1207 Console
.WriteLine ("Error: invalid parameter.");
1211 public void SetUseSimpleReader (string[] parms
)
1213 if (parms
.Length
!= 2) {
1214 Console
.WriteLine ("Error: wrong number of parameters");
1217 string parm
= parms
[1].ToUpper ();
1218 if (parm
.Equals ("TRUE"))
1219 UseSimpleReader
= true;
1220 else if (parm
.Equals ("FALSE"))
1221 UseSimpleReader
= false;
1223 Console
.WriteLine ("Error: invalid parameter.");
1226 public void SetupSilentMode (string[] parms
)
1228 if (parms
.Length
!= 2) {
1229 Console
.WriteLine ("Error: wrong number of parameters");
1232 string parm
= parms
[1].ToUpper ();
1233 if (parm
.Equals ("TRUE"))
1235 else if (parm
.Equals ("FALSE"))
1238 Console
.WriteLine ("Error: invalid parameter.");
1241 public void SetInternalVariable(string[] parms
)
1243 if (parms
.Length
< 2) {
1244 Console
.WriteLine ("Error: wrong number of parameters.");
1247 string parm
= parms
[1];
1248 StringBuilder ps
= new StringBuilder ();
1250 for (int i
= 2; i
< parms
.Length
; i
++)
1251 ps
.Append (parms
[i
]);
1253 internalVariables
[parm
] = ps
.ToString ();
1256 public void UnSetInternalVariable(string[] parms
)
1258 if (parms
.Length
!= 2) {
1259 Console
.WriteLine ("Error: wrong number of parameters.");
1262 string parm
= parms
[1];
1265 internalVariables
.Remove (parm
);
1266 } catch(Exception e
) {
1267 Console
.WriteLine ("Error: internal variable does not exist: " + e
.Message
);
1271 public void ShowInternalVariable(string[] parms
)
1273 string internalVariableValue
= "";
1275 if (parms
.Length
!= 2) {
1276 Console
.WriteLine ("Error: wrong number of parameters.");
1280 string parm
= parms
[1];
1282 if (GetInternalVariable(parm
, out internalVariableValue
) == true)
1283 Console
.WriteLine ("Internal Variable - Name: " +
1284 parm
+ " Value: " + internalVariableValue
);
1287 public bool GetInternalVariable(string name
, out string sValue
)
1290 bool valueReturned
= false;
1293 if (internalVariables
.ContainsKey (name
) == true) {
1294 sValue
= (string) internalVariables
[name
];
1295 valueReturned
= true;
1298 Console
.WriteLine ("Error: internal variable does not exist.");
1301 catch(Exception e
) {
1302 Console
.WriteLine ("Error: internal variable does not exist: "+ e
.Message
);
1304 return valueReturned
;
1307 public void SetupExternalProvider(string[] parms
)
1309 if (parms
.Length
!= 3) {
1310 Console
.WriteLine ("Error: Wrong number of parameters.");
1313 provider
= "LOADEXTPROVIDER";
1314 providerAssembly
= parms
[1];
1315 providerConnectionClass
= parms
[2];
1318 public bool LoadExternalProvider ()
1322 bool success
= false;
1324 // For example: for the MySQL provider in Mono.Data.MySql
1325 // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
1326 // \ConnectionString dbname=test
1328 // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
1334 OutputLine ("Loading external provider...");
1336 Assembly ps
= Assembly
.Load (providerAssembly
);
1337 conType
= ps
.GetType (providerConnectionClass
);
1338 conn
= (IDbConnection
) Activator
.CreateInstance (conType
);
1341 OutputLine ("External provider loaded.");
1342 UseParameters
= false;
1343 } catch(FileNotFoundException f
) {
1344 msg
= "Error: unable to load the assembly of the provider: " + providerAssembly
+ " : " + f
.Message
;
1345 Console
.WriteLine(msg
);
1347 catch(Exception e
) {
1348 msg
= "Error: unable to load the assembly of the provider: " + providerAssembly
+ " : " + e
.Message
;
1349 Console
.WriteLine(msg
);
1354 // used for outputting message, but if silent is set,
1356 public void OutputLine (string line
)
1358 if (silent
== false)
1362 // used for outputting the header columns of a result
1363 public void OutputHeader (string line
)
1365 if (showHeader
== true)
1369 // OutputData() - used for outputting data
1370 // if an output filename is set, then the data will
1371 // go to a file; otherwise, it will go to the Console.
1372 public void OutputData(string line
)
1374 if (outputFilestream
== null)
1375 Console
.WriteLine (line
);
1377 outputFilestream
.WriteLine (line
);
1380 // HandleCommand - handle SqlSharpCli commands entered
1381 public void HandleCommand (string entry
)
1385 parms
= entry
.Split (new char[1] {' '}
);
1386 string userCmd
= parms
[0].ToUpper ();
1389 case "\\LISTPROVIDERS":
1395 ChangeProvider (parms
);
1397 case "\\CONNECTIONSTRING":
1399 ChangeConnectionString (parms
, entry
);
1401 case "\\LOADEXTPROVIDER":
1402 SetupExternalProvider (parms
);
1411 SetupSilentMode (parms
);
1417 // Execute SQL Commands or Queries
1419 Console
.WriteLine ("Error: connection is not Open.");
1420 else if (conn
.State
== ConnectionState
.Closed
)
1421 Console
.WriteLine ("Error: connection is not Open.");
1424 Console
.WriteLine ("Error: SQL Buffer is empty.");
1426 buff
= build
.ToString ();
1432 case "\\EXENONQUERY":
1434 Console
.WriteLine ("Error: connection is not Open.");
1435 else if (conn
.State
== ConnectionState
.Closed
)
1436 Console
.WriteLine ("Error: connection is not Open.");
1439 Console
.WriteLine ("Error: SQL Buffer is empty.");
1441 buff
= build
.ToString ();
1442 ExecuteSqlNonQuery (buff
);
1449 Console
.WriteLine ("Error: connection is not Open.");
1450 else if (conn
.State
== ConnectionState
.Closed
)
1451 Console
.WriteLine ("Error: connection is not Open.");
1454 Console
.WriteLine ("Error: SQL Buffer is empty.");
1456 buff
= build
.ToString ();
1457 ExecuteSqlScalar (buff
);
1463 // \exexml OUTPUT_FILENAME
1465 Console
.WriteLine ("Error: connection is not Open.");
1466 else if (conn
.State
== ConnectionState
.Closed
)
1467 Console
.WriteLine ("Error: connection is not Open.");
1470 Console
.WriteLine ("Error: SQL Buffer is empty.");
1472 buff
= build
.ToString ();
1473 ExecuteSqlXml (buff
, parms
);
1479 SetupInputCommandsFile (parms
);
1482 SetupOutputResultsFile (parms
);
1485 // Load file into SQL buffer: \load FILENAME
1486 LoadBufferFromFile (parms
);
1489 // Save SQL buffer to file: \save FILENAME
1490 SaveBufferToFile (parms
);
1498 // show the defaults for provider and connection strings
1502 BuildConnectionString ();
1511 // reset (clear) the query buffer
1515 // sets internal variable
1517 SetInternalVariable (parms
);
1520 // deletes internal variable
1522 UnSetInternalVariable (parms
);
1525 ShowInternalVariable (parms
);
1529 Console
.WriteLine ("SQL Buffer is empty.");
1531 Console
.WriteLine ("SQL Bufer:\n" + buff
);
1533 case "\\USEPARAMETERS":
1534 SetUseParameters (parms
);
1536 case "\\USESIMPLEREADER":
1537 SetUseSimpleReader (parms
);
1541 Console
.WriteLine ("Error: Unknown user command.");
1546 public void ListProviders()
1548 DataTable table
= DbProviderFactories
.GetFactoryClasses();
1549 Console
.WriteLine("List of Providers:");
1550 for (int r
= 0; r
< table
.Rows
.Count
; r
++)
1552 Console
.WriteLine("---------------------");
1553 Console
.WriteLine(" Name: " + table
.Rows
[r
][0].ToString());
1554 Console
.WriteLine(" Description: " + table
.Rows
[r
][1].ToString());
1555 Console
.WriteLine(" InvariantName: " + table
.Rows
[r
][2].ToString());
1556 Console
.WriteLine(" AssemblyQualifiedName: " + table
.Rows
[r
][3].ToString());
1558 Console
.WriteLine("---------------------");
1559 Console
.WriteLine("Providers found: " + table
.Rows
.Count
.ToString());
1562 public void DealWithArgs(string[] args
)
1564 for (int a
= 0; a
< args
.Length
; a
++) {
1565 if (args
[a
].Substring (0,1).Equals ("-")) {
1566 string arg
= args
[a
].ToUpper ().Substring (1, args
[a
].Length
- 1);
1572 if (a
+ 1 >= args
.Length
)
1573 Console
.WriteLine ("Error: Missing FILENAME for -f switch");
1575 inputFilename
= args
[a
+ 1];
1576 inputFilestream
= new StreamReader (inputFilename
);
1580 if (a
+ 1 >= args
.Length
)
1581 Console
.WriteLine ("Error: Missing FILENAME for -o switch");
1583 outputFilename
= args
[a
+ 1];
1584 outputFilestream
= new StreamWriter (outputFilename
);
1588 Console
.WriteLine ("Error: Unknow switch: " + args
[a
]);
1595 public string GetPasswordFromConsole ()
1597 StringBuilder pb
= new StringBuilder ();
1598 Console
.Write ("\nPassword: ");
1599 ConsoleKeyInfo cki
= Console
.ReadKey (true);
1601 while (cki
.Key
!= ConsoleKey
.Enter
) {
1602 if (cki
.Key
== ConsoleKey
.Backspace
) {
1603 if (pb
.Length
> 0) {
1604 pb
.Remove (pb
.Length
- 1, 1);
1605 Console
.Write ("\b");
1606 Console
.Write (" ");
1607 Console
.Write ("\b");
1610 pb
.Append (cki
.KeyChar
);
1611 Console
.Write ("*");
1613 cki
= Console
.ReadKey (true);
1616 Console
.WriteLine ();
1617 return pb
.ToString ();
1620 public string ReadSqlSharpCommand()
1624 if (inputFilestream
== null) {
1625 if (silent
== false)
1626 Console
.Error
.Write ("\nSQL# ");
1627 entry
= Console
.ReadLine ();
1631 entry
= inputFilestream
.ReadLine ();
1632 if (entry
== null) {
1633 OutputLine ("Executing SQL# Commands from file done.");
1636 catch (Exception e
) {
1637 Console
.WriteLine ("Error: Reading command from file: " + e
.Message
);
1639 if (silent
== false)
1640 Console
.Error
.Write ("\nSQL# ");
1641 entry
= Console
.ReadLine ();
1646 public string ReadConnectionOption(string option
, string defaultVal
)
1648 Console
.Error
.Write ("\nConnectionString Option: {0} [{1}] SQL# ", option
, defaultVal
);
1649 return Console
.ReadLine ();
1652 public void BuildConnectionString ()
1654 if (factory
== null) {
1655 Console
.WriteLine("Provider is not set.");
1659 DbConnectionStringBuilder sb
= factory
.CreateConnectionStringBuilder ();
1660 if (!connectionString
.Equals(String
.Empty
))
1661 sb
.ConnectionString
= connectionString
;
1664 foreach (string key
in sb
.Keys
) {
1665 if (key
.ToUpper().Equals("PASSWORD") || key
.ToUpper().Equals("PWD")) {
1666 string pwd
= GetPasswordFromConsole ();
1669 } catch(Exception e
) {
1670 Console
.Error
.WriteLine("Error: unable to set key. Reason: " + e
.Message
);
1674 string defaultVal
= sb
[key
].ToString ();
1676 val
= ReadConnectionOption (key
, defaultVal
);
1677 if (val
.ToUpper ().Equals ("\\STOP"))
1682 } catch(Exception e
) {
1683 Console
.Error
.WriteLine("Error: unable to set key. Reason: " + e
.Message
);
1691 Console
.Error
.WriteLine("Warning: your provider does not subclass DbConnectionStringBuilder fully.");
1695 connectionString
= sb
.ConnectionString
;
1696 Console
.WriteLine("ConnectionString is set.");
1699 public void Run (string[] args
)
1701 DealWithArgs (args
);
1706 if (silent
== false) {
1707 Console
.WriteLine ("Welcome to SQL#. The interactive SQL command-line client ");
1708 Console
.WriteLine ("for Mono.Data. See http://www.mono-project.com/ for more details.\n");
1714 while (entry
.ToUpper ().Equals ("\\Q") == false &&
1715 entry
.ToUpper ().Equals ("\\QUIT") == false) {
1717 while ((entry
= ReadSqlSharpCommand ()) == "") {}
1720 if (entry
.Substring(0,1).Equals ("\\")) {
1721 HandleCommand (entry
);
1723 else if (entry
.IndexOf(";") >= 0) {
1724 // most likely the end of SQL Command or Query found
1727 Console
.WriteLine ("Error: connection is not Open.");
1728 else if (conn
.State
== ConnectionState
.Closed
)
1729 Console
.WriteLine ("Error: connection is not Open.");
1731 if (build
== null) {
1732 build
= new StringBuilder ();
1734 build
.Append (entry
);
1735 //build.Append ("\n");
1736 buff
= build
.ToString ();
1742 // most likely a part of a SQL Command or Query found
1743 // append this part of the SQL
1744 if (build
== null) {
1745 build
= new StringBuilder ();
1747 build
.Append (entry
+ "\n");
1748 buff
= build
.ToString ();
1752 if (outputFilestream
!= null)
1753 outputFilestream
.Close ();
1757 public enum BindVariableCharacter
{
1758 Colon
, // ':' - named parameter - :name
1759 At
, // '@' - named parameter - @name
1760 QuestionMark
, // '?' - positioned parameter - ?
1761 SquareBrackets
// '[]' - delimited named parameter - [name]
1764 public class ParametersBuilder
1766 private BindVariableCharacter bindCharSetting
;
1767 private char bindChar
;
1768 private IDataParameterCollection parms
;
1770 private IDbCommand cmd
;
1772 private void SetBindCharacter ()
1774 switch(bindCharSetting
) {
1775 case BindVariableCharacter
.Colon
:
1778 case BindVariableCharacter
.At
:
1781 case BindVariableCharacter
.SquareBrackets
:
1784 case BindVariableCharacter
.QuestionMark
:
1790 public ParametersBuilder (IDbCommand command
, BindVariableCharacter bindVarChar
)
1793 sql
= cmd
.CommandText
;
1794 parms
= cmd
.Parameters
;
1795 bindCharSetting
= bindVarChar
;
1799 public char ParameterMarkerCharacter
{
1805 public int ParseParameters ()
1809 char[] chars
= sql
.ToCharArray ();
1810 bool bStringConstFound
= false;
1812 for (int i
= 0; i
< chars
.Length
; i
++) {
1813 if (chars
[i
] == '\'') {
1814 if (bStringConstFound
== true)
1815 bStringConstFound
= false;
1817 bStringConstFound
= true;
1819 else if (chars
[i
] == bindChar
&&
1820 bStringConstFound
== false) {
1821 if (bindChar
!= '?') {
1822 StringBuilder parm
= new StringBuilder ();
1824 if (bindChar
.Equals ('[')) {
1825 bool endingBracketFound
= false;
1826 while (i
<= chars
.Length
) {
1828 if (i
== chars
.Length
)
1829 ch
= ' '; // a space
1833 if (Char
.IsLetterOrDigit (ch
) || ch
== ' ') {
1836 else if (ch
== ']') {
1837 endingBracketFound
= true;
1838 string p
= parm
.ToString ();
1843 else throw new Exception("SQL Parser Error: Invalid character in parameter name");
1847 if (endingBracketFound
== false)
1848 throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
1851 while (i
<= chars
.Length
) {
1853 if (i
== chars
.Length
)
1854 ch
= ' '; // a space
1858 if (Char
.IsLetterOrDigit(ch
)) {
1863 string p
= parm
.ToString ();
1874 // placeholder paramaeter for ?
1875 string p
= numParms
.ToString ();
1884 public void AddParameter (string p
)
1886 Console
.WriteLine ("Add Parameter: " + p
);
1887 if (parms
.Contains (p
) == false) {
1888 IDataParameter prm
= cmd
.CreateParameter ();
1889 prm
.ParameterName
= p
;
1890 prm
.Direction
= ParameterDirection
.Input
;
1891 prm
.DbType
= DbType
.String
; // default
1892 prm
.Value
= ""; // default
1893 cmd
.Parameters
.Add(prm
);
1899 public class SqlSharpDriver
1901 public static void Main (string[] args
)
1903 SqlSharpCli sqlCommandLineEngine
= new SqlSharpCli ();
1904 sqlCommandLineEngine
.Run (args
);