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 SqlSharpCli.cs /r:System.Data.dll
15 // $ mono SqlSharpCli.exe
18 // $ mint SqlSharpCli.exe
20 // To run batch commands and get the output, do something like:
21 // $ cat commands.txt | mono SqlSharpCli.exe > results.txt
24 // Daniel Morgan <danielmorgan@verizon.net>
26 // (C)Copyright 2002-2004 Daniel Morgan
30 using System
.Collections
;
32 using System
.Data
.Common
;
33 using System
.Data
.OleDb
;
34 using System
.Data
.SqlClient
;
36 using System
.Reflection
;
37 using System
.Runtime
.Remoting
;
40 namespace Mono
.Data
.SqlSharp
{
42 public enum FileFormat
{
50 // SQL Sharp - Command Line Interface
51 public class SqlSharpCli
{
54 private bool UseParameters
= true;
55 private bool UseSimpleReader
= false;
57 private IDbConnection conn
= null;
59 private string provider
= ""; // name of internal provider
60 // {OleDb,SqlClient,MySql,Odbc,Oracle,
61 // PostgreSql,SqlLite,Sybase,Tds} however, it
62 // can be set to LOADEXTPROVIDER to load an external provider
63 private string providerAssembly
= "";
64 // filename of assembly
65 // for example: "Mono.Data.MySql"
66 private string providerConnectionClass
= "";
68 // in the provider assembly that implements the IDbConnection
69 // interface. for example: "Mono.Data.MySql.MySqlConnection"
71 private StringBuilder build
= null; // SQL string to build
72 private string buff
= ""; // SQL string buffer
74 private string connectionString
= "";
76 private string inputFilename
= "";
77 private string outputFilename
= "";
78 private StreamReader inputFilestream
= null;
79 private StreamWriter outputFilestream
= null;
81 private FileFormat outputFileFormat
= FileFormat
.Html
;
83 private bool silent
= false;
84 private bool showHeader
= true;
86 private Hashtable internalVariables
= new Hashtable();
88 // DisplayResult - used to Read() display a result set
89 // called by DisplayData()
90 public void DisplayResult(IDataReader reader
, DataTable schemaTable
) {
92 const string zero
= "0";
93 StringBuilder column
= null;
94 StringBuilder line
= null;
95 StringBuilder hdrUnderline
= null;
103 char spacingChar
= ' '; // a space
104 char underlineChar
= '='; // an equal sign
106 string dataType
; // .NET Type
108 //string dataTypeName; // native Database type
109 DataRow row
; // schema row
111 line
= new StringBuilder();
112 hdrUnderline
= new StringBuilder();
114 OutputLine("Fields in Query Result: " +
118 for(c
= 0; c
< schemaTable
.Rows
.Count
; c
++) {
120 DataRow schemaRow
= schemaTable
.Rows
[c
];
121 string columnHeader
= (string) schemaRow
["ColumnName"];
122 if(columnHeader
.Equals(""))
123 columnHeader
= "?column?";
124 if(columnHeader
.Length
> 32)
125 columnHeader
= columnHeader
.Substring(0,32);
128 columnSize
= (int) schemaRow
["ColumnSize"];
129 theType
= (Type
) schemaRow
["DataType"];
130 dataType
= theType
.ToString();
133 case "System.DateTime":
136 case "System.Boolean":
141 hdrLen
= (columnHeader
.Length
> columnSize
) ?
142 columnHeader
.Length
: columnSize
;
149 line
.Append(columnHeader
);
150 if(columnHeader
.Length
< hdrLen
) {
151 spacing
= hdrLen
- columnHeader
.Length
;
152 line
.Append(spacingChar
, spacing
);
154 hdrUnderline
.Append(underlineChar
, hdrLen
);
157 hdrUnderline
.Append(" ");
159 OutputHeader(line
.ToString());
162 OutputHeader(hdrUnderline
.ToString());
169 while(reader
.Read()) {
172 line
= new StringBuilder();
173 for(c
= 0; c
< reader
.FieldCount
; c
++) {
175 string dataValue
= "";
176 column
= new StringBuilder();
179 row
= schemaTable
.Rows
[c
];
180 string colhdr
= (string) row
["ColumnName"];
181 if(colhdr
.Equals(""))
183 if(colhdr
.Length
> 32)
184 colhdr
= colhdr
.Substring(0, 32);
186 columnSize
= (int) row
["ColumnSize"];
187 theType
= (Type
) row
["DataType"];
188 dataType
= theType
.ToString();
191 case "System.DateTime":
194 case "System.Boolean":
199 columnSize
= (colhdr
.Length
> columnSize
) ?
200 colhdr
.Length
: columnSize
;
209 if(reader
.IsDBNull(c
)) {
216 if(dataType
.Equals("System.DateTime")) {
217 // display date in ISO format
218 // "YYYY-MM-DD HH:MM:SS"
219 dt
= reader
.GetDateTime(c
);
220 sb
= new StringBuilder();
223 sb
.Append("000" + dt
.Year
);
224 else if(dt
.Year
< 100)
225 sb
.Append("00" + dt
.Year
);
226 else if(dt
.Year
< 1000)
227 sb
.Append("0" + dt
.Year
);
233 sb
.Append(zero
+ dt
.Month
);
239 sb
.Append(zero
+ dt
.Day
);
245 sb
.Append(zero
+ dt
.Hour
);
251 sb
.Append(zero
+ dt
.Minute
);
253 sb
.Append(dt
.Minute
);
257 sb
.Append(zero
+ dt
.Second
);
259 sb
.Append(dt
.Second
);
261 dataValue
= sb
.ToString();
264 dataValue
= reader
.GetValue(c
).ToString();
267 dataLen
= dataValue
.Length
;
273 dataValue
= dataValue
.Substring(0,32);
277 columnSize
= columnSize
> dataLen
? columnSize
: dataLen
;
281 if(columnSize
< colhdr
.Length
) {
282 spacing
= colhdr
.Length
- columnSize
;
283 column
.Append(spacingChar
, spacing
);
285 if(dataLen
< columnSize
) {
286 spacing
= columnSize
- dataLen
;
287 column
.Append(spacingChar
, spacing
);
292 case "System.Single":
293 case "System.Double":
294 case "System.Decimal":
295 outData
= column
.ToString() + dataValue
;
298 outData
= dataValue
+ column
.ToString();
305 line
.Append(outData
);
308 OutputData(line
.ToString());
311 OutputLine("\nRows retrieved: " + rows
.ToString());
314 public void OutputDataToHtmlFile(IDataReader rdr
, DataTable dt
) {
316 StringBuilder strHtml
= new StringBuilder();
318 strHtml
.Append("<html> \n <head> <title>");
319 strHtml
.Append("Results");
320 strHtml
.Append("</title> </head>");
321 strHtml
.Append("<body>");
322 strHtml
.Append("<h1> Results </h1>");
323 strHtml
.Append("<table border=1>");
325 outputFilestream
.WriteLine(strHtml
.ToString());
328 strHtml
= new StringBuilder();
330 strHtml
.Append("<tr>");
331 foreach (DataRow schemaRow
in dt
.Rows
) {
332 strHtml
.Append("<td> <b>");
333 object dataObj
= schemaRow
["ColumnName"];
334 string sColumnName
= dataObj
.ToString();
335 strHtml
.Append(sColumnName
);
336 strHtml
.Append("</b> </td>");
338 strHtml
.Append("</tr>");
339 outputFilestream
.WriteLine(strHtml
.ToString());
343 string dataValue
= "";
346 strHtml
= new StringBuilder();
348 strHtml
.Append("<tr>");
349 for(col
= 0; col
< rdr
.FieldCount
; col
++) {
352 if(rdr
.IsDBNull(col
) == true)
355 object obj
= rdr
.GetValue(col
);
356 dataValue
= obj
.ToString();
358 strHtml
.Append("<td>");
359 strHtml
.Append(dataValue
);
360 strHtml
.Append("</td>");
362 strHtml
.Append("\t\t</tr>");
363 outputFilestream
.WriteLine(strHtml
.ToString());
366 outputFilestream
.WriteLine(" </table> </body> \n </html>");
370 // DisplayData - used to display any Result Sets
371 // from execution of SQL SELECT Query or Queries
372 // called by DisplayData.
373 // ExecuteSql() only calls this function
374 // for a Query, it does not get
376 public void DisplayData(IDataReader reader
) {
378 DataTable schemaTable
= null;
381 OutputLine("Display any result sets...");
384 // by Default, SqlDataReader has the
385 // first Result set if any
388 OutputLine("Display the result set " + ResultSet
);
390 schemaTable
= reader
.GetSchemaTable();
392 if(reader
.FieldCount
> 0) {
393 // SQL Query (SELECT)
394 // RecordsAffected -1 and DataTable has a reference
395 OutputQueryResult(reader
, schemaTable
);
397 else if(reader
.RecordsAffected
>= 0) {
398 // SQL Command (INSERT, UPDATE, or DELETE)
399 // RecordsAffected >= 0
400 Console
.WriteLine("SQL Command Records Affected: " + reader
.RecordsAffected
);
403 // SQL Command (not INSERT, UPDATE, nor DELETE)
404 // RecordsAffected -1 and DataTable has a null reference
405 Console
.WriteLine("SQL Command Executed.");
408 // get next result set (if anymore is left)
409 } while(reader
.NextResult());
412 // display the result in a simple way
413 // new ADO.NET providers may have not certain
414 // things implemented yet, such as, TableSchema
416 public void DisplayDataSimple(IDataReader reader
) {
419 Console
.WriteLine("Reading Data using simple reader...");
420 while(reader
.Read()){
422 Console
.WriteLine("Row: " + row
);
423 for(int col
= 0; col
< reader
.FieldCount
; col
++) {
425 Console
.WriteLine(" Field: " + co
);
427 string dname
= (string) reader
.GetName(col
);
430 if(dname
.Equals(String
.Empty
))
432 Console
.WriteLine(" Name: " + dname
);
435 if (reader
.IsDBNull(col
))
438 dvalue
= reader
.GetValue(col
).ToString();
439 Console
.WriteLine(" Value: " + dvalue
);
442 Console
.WriteLine("\n" + row
+ " ROWS RETRIEVED\n");
445 public void OutputQueryResult(IDataReader dreader
, DataTable dtable
) {
446 if(outputFilestream
== null) {
447 DisplayResult(dreader
, dtable
);
450 switch(outputFileFormat
) {
451 case FileFormat
.Normal
:
452 DisplayResult(dreader
, dtable
);
454 case FileFormat
.Html
:
455 OutputDataToHtmlFile(dreader
, dtable
);
458 Console
.WriteLine("Error: Output data file format not supported.");
464 public void BuildParameters(IDbCommand cmd
) {
465 if(UseParameters
== true) {
467 ParametersBuilder parmsBuilder
=
468 new ParametersBuilder(cmd
,
469 BindVariableCharacter
.Colon
);
471 Console
.WriteLine("Get Parameters (if any)...");
472 parmsBuilder
.ParseParameters();
473 IList parms
= (IList
) cmd
.Parameters
;
475 Console
.WriteLine("Print each parm...");
476 for(int p
= 0; p
< parms
.Count
; p
++) {
479 IDataParameter prm
= (IDataParameter
) parms
[p
];
480 theParmName
= prm
.ParameterName
;
484 if(parmsBuilder
.ParameterMarkerCharacter
== '?') {
485 Console
.Write("Enter Parameter " +
488 inValue
= Console
.ReadLine();
492 found
= GetInternalVariable(theParmName
, out inValue
);
497 Console
.Write("Enter Parameter " + (p
+ 1).ToString() +
498 ": " + theParmName
+ ": ");
499 inValue
= Console
.ReadLine();
508 // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
509 public void ExecuteSql(string sql
) {
512 Console
.WriteLine("Execute SQL: " + sql
);
514 IDbCommand cmd
= null;
515 IDataReader reader
= null;
517 cmd
= conn
.CreateCommand();
519 // set command properties
520 cmd
.CommandType
= CommandType
.Text
;
521 cmd
.CommandText
= sql
;
522 cmd
.Connection
= conn
;
524 BuildParameters(cmd
);
527 reader
= cmd
.ExecuteReader();
529 if(UseSimpleReader
== false)
532 DisplayDataSimple(reader
);
539 // msg = "Error: " + e.Message;
540 Console
.WriteLine(msg
);
541 //if(reader != null) {
542 // if(reader.IsClosed == false)
553 // ExecuteSql - Execute the SQL Commands (no SELECTs)
554 public void ExecuteSqlNonQuery(string sql
) {
557 Console
.WriteLine("Execute SQL Non Query: " + sql
);
559 IDbCommand cmd
= null;
560 int rowsAffected
= -1;
562 cmd
= conn
.CreateCommand();
564 // set command properties
565 cmd
.CommandType
= CommandType
.Text
;
566 cmd
.CommandText
= sql
;
567 cmd
.Connection
= conn
;
569 BuildParameters(cmd
);
572 rowsAffected
= cmd
.ExecuteNonQuery();
574 Console
.WriteLine("Rows affected: " + rowsAffected
);
577 msg
= "Error: " + e
.Message
;
578 Console
.WriteLine(msg
);
586 public void ExecuteSqlScalar(string sql
) {
589 Console
.WriteLine("Execute SQL Scalar: " + sql
);
591 IDbCommand cmd
= null;
592 string retrievedValue
= "";
594 cmd
= conn
.CreateCommand();
596 // set command properties
597 cmd
.CommandType
= CommandType
.Text
;
598 cmd
.CommandText
= sql
;
599 cmd
.Connection
= conn
;
601 BuildParameters(cmd
);
604 retrievedValue
= (string) cmd
.ExecuteScalar().ToString();
605 Console
.WriteLine("Retrieved value: " + retrievedValue
);
608 msg
= "Error: " + e
.Message
;
609 Console
.WriteLine(msg
);
617 public void ExecuteSqlXml(string sql
, string[] parms
) {
618 string filename
= "";
620 if(parms
.Length
!= 2) {
621 Console
.WriteLine("Error: wrong number of parameters");
628 Console
.WriteLine("Error: Unable to setup output results file. " +
634 Console
.WriteLine("Execute SQL XML: " + sql
);
636 IDbCommand cmd
= null;
638 cmd
= conn
.CreateCommand();
640 // set command properties
641 cmd
.CommandType
= CommandType
.Text
;
642 cmd
.CommandText
= sql
;
643 cmd
.Connection
= conn
;
645 BuildParameters(cmd
);
647 Console
.WriteLine("Creating new DataSet...");
648 DataSet dataSet
= new DataSet ();
650 Console
.WriteLine("Creating new provider DataAdapter...");
651 DbDataAdapter adapter
= CreateNewDataAdapter (cmd
, conn
);
653 Console
.WriteLine("Filling DataSet via Data Adapter...");
654 adapter
.Fill (dataSet
);
656 Console
.WriteLine ("Write DataSet to XML file: " +
658 dataSet
.WriteXml (filename
);
660 Console
.WriteLine ("Done.");
662 catch(Exception exexml
) {
663 Console
.WriteLine("Error: Execute SQL XML Failure: " +
668 public DbDataAdapter
CreateNewDataAdapter (IDbCommand command
,
669 IDbConnection connection
) {
671 DbDataAdapter adapter
= null;
675 adapter
= (DbDataAdapter
) new OleDbDataAdapter ();
678 adapter
= (DbDataAdapter
) new SqlDataAdapter ();
680 case "LOADEXTPROVIDER":
681 adapter
= CreateExternalDataAdapter (command
, connection
);
686 Console
.WriteLine("Error: Data Adapter not found in provider.");
689 IDbDataAdapter dbAdapter
= (IDbDataAdapter
) adapter
;
690 dbAdapter
.SelectCommand
= command
;
695 public DbDataAdapter
CreateExternalDataAdapter (IDbCommand command
,
696 IDbConnection connection
) {
698 DbDataAdapter adapter
= null;
700 Assembly ass
= Assembly
.Load (providerAssembly
);
701 Type
[] types
= ass
.GetTypes ();
702 foreach (Type t
in types
) {
703 if (t
.IsSubclassOf (typeof(System
.Data
.Common
.DbDataAdapter
))) {
704 if(t
.Namespace
.Equals(conType
.Namespace
))
705 adapter
= (DbDataAdapter
) Activator
.CreateInstance (t
);
712 // like ShowHelp - but only show at the beginning
713 // only the most important commands are shown
714 // like help and quit
715 public void StartupHelp() {
716 Console
.WriteLine(@"Type: \Q to quit");
717 Console
.WriteLine(@" \ConnectionString to set the ConnectionString");
718 Console
.WriteLine(@" \Provider to set the Provider:");
719 Console
.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,DB2,");
720 Console
.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds)");
721 Console
.WriteLine(@" \Open to open the connection");
722 Console
.WriteLine(@" \Close to close the connection");
723 Console
.WriteLine(@" \e to execute SQL query (SELECT)");
724 Console
.WriteLine(@" \h to show help (all commands).");
725 Console
.WriteLine(@" \defaults to show default variables.");
729 // ShowHelp - show the help - command a user can enter
730 public void ShowHelp() {
731 Console
.WriteLine("");
732 Console
.WriteLine(@"Type: \Q to quit");
733 Console
.WriteLine(@" \ConnectionString to set the ConnectionString");
734 Console
.WriteLine(@" \Provider to set the Provider:");
735 Console
.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,MSODBC,");
736 Console
.WriteLine(@" Oracle,PostgreSql,Sqlite,Sybase,Tds}");
737 Console
.WriteLine(@" \Open to open the connection");
738 Console
.WriteLine(@" \Close to close the connection");
739 Console
.WriteLine(@" \e to execute SQL query (SELECT)");
740 Console
.WriteLine(@" \exenonquery to execute an SQL non query (not a SELECT).");
741 Console
.WriteLine(@" \exescalar to execute SQL to get a single row and single column.");
742 Console
.WriteLine(@" \exexml FILENAME to execute SQL and save output to XML file.");
743 Console
.WriteLine(@" \f FILENAME to read a batch of SQL# commands from file.");
744 Console
.WriteLine(@" \o FILENAME to write result of commands executed to file.");
745 Console
.WriteLine(@" \load FILENAME to load from file SQL commands into SQL buffer.");
746 Console
.WriteLine(@" \save FILENAME to save SQL commands from SQL buffer to file.");
747 Console
.WriteLine(@" \h to show help (all commands).");
748 Console
.WriteLine(@" \defaults to show default variables, such as,");
749 Console
.WriteLine(@" Provider and ConnectionString.");
750 Console
.WriteLine(@" \s {TRUE, FALSE} to silent messages.");
751 Console
.WriteLine(@" \r to reset or clear the query buffer.");
753 Console
.WriteLine(@" \set NAME VALUE to set an internal variable.");
754 Console
.WriteLine(@" \unset NAME to remove an internal variable.");
755 Console
.WriteLine(@" \variable NAME to display the value of an internal variable.");
756 Console
.WriteLine(@" \loadextprovider ASSEMBLY CLASS to load the provider");
757 Console
.WriteLine(@" use the complete name of its assembly and");
758 Console
.WriteLine(@" its Connection class.");
759 Console
.WriteLine(@" \print - show what's in the SQL buffer now.");
760 Console
.WriteLine(@" \UseParameters (TRUE,FALSE) to use parameters when executing SQL.");
761 Console
.WriteLine(@" \UseSimpleReader (TRUE,FALSE) to use simple reader when displaying results.");
765 public bool WaitForEnterKey() {
766 Console
.Write("Waiting... Press Enter key to continue. ");
767 string entry
= Console
.ReadLine();
768 if (entry
.ToUpper() == "Q")
773 // ShowDefaults - show defaults for connection variables
774 public void ShowDefaults() {
776 if(provider
.Equals(""))
777 Console
.WriteLine("Provider is not set.");
779 Console
.WriteLine("The default Provider is " + provider
);
780 if(provider
.Equals("LOADEXTPROVIDER")) {
781 Console
.WriteLine(" Assembly: " +
783 Console
.WriteLine(" Connection Class: " +
784 providerConnectionClass
);
788 if(connectionString
.Equals(""))
789 Console
.WriteLine("ConnectionString is not set.");
791 Console
.WriteLine("The default ConnectionString is: ");
792 Console
.WriteLine(" \"" + connectionString
+ "\"");
797 // OpenDataSource - open connection to the data source
798 public void OpenDataSource() {
801 Console
.WriteLine("Attempt to open connection...");
806 conn
= new OleDbConnection();
809 conn
= new SqlConnection();
811 case "LOADEXTPROVIDER":
812 if(LoadExternalProvider() == false)
816 Console
.WriteLine("Error: Bad argument or provider not supported.");
821 msg
= "Error: Unable to create Connection object because: " +
823 Console
.WriteLine(msg
);
827 conn
.ConnectionString
= connectionString
;
831 if(conn
.State
== ConnectionState
.Open
)
832 Console
.WriteLine("Open was successfull.");
835 msg
= "Exception Caught Opening. " + e
.Message
;
836 Console
.WriteLine(msg
);
841 // CloseDataSource - close the connection to the data source
842 public void CloseDataSource() {
846 Console
.WriteLine("Attempt to Close...");
849 Console
.WriteLine("Close was successfull.");
852 msg
= "Exeception Caught Closing. " + e
.Message
;
853 Console
.WriteLine(msg
);
859 // ChangeProvider - change the provider string variable
860 public void ChangeProvider(string[] parms
) {
864 if(parms
.Length
== 2) {
865 string parm
= parms
[1].ToUpper();
868 extp
= new string[3] {
870 @"System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
871 "System.Data.OracleClient.OracleConnection"};
872 SetupExternalProvider(extp
);
873 UseParameters
= false;
874 UseSimpleReader
= false;
877 extp
= new string[3] {
879 @"Mono.Data.TdsClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
880 "Mono.Data.TdsClient.TdsConnection"};
881 SetupExternalProvider(extp
);
882 UseParameters
= false;
883 UseSimpleReader
= false;
886 extp
= new string[3] {
888 @"Mono.Data.SybaseClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
889 "Mono.Data.SybaseClient.SybaseConnection"};
890 SetupExternalProvider(extp
);
891 UseParameters
= false;
892 UseSimpleReader
= false;
896 extp
= new string[3] {
898 @"ByteFX.Data, Version=0.7.6.1, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
899 "ByteFX.Data.MySqlClient.MySqlConnection"};
900 SetupExternalProvider(extp
);
901 UseParameters
= false;
902 UseSimpleReader
= false;
905 extp
= new string[3] {
907 @"Mono.Data.SqliteClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756",
908 "Mono.Data.SqliteClient.SqliteConnection"};
909 SetupExternalProvider(extp
);
910 UseParameters
= false;
911 UseSimpleReader
= true;
914 UseParameters
= false;
915 UseSimpleReader
= false;
918 case "ODBC": // for MS NET 1.1 and above
919 extp
= new string[3] {
921 @"System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
922 "System.Data.Odbc.OdbcConnection"};
923 SetupExternalProvider(extp
);
924 UseParameters
= false;
925 UseSimpleReader
= false;
927 case "MSODBC": // for MS NET 1.0
928 extp
= new string[3] {
930 @"Microsoft.Data.Odbc, Culture=neutral, PublicKeyToken=b77a5c561934e089, Version=1.0.3300.0",
931 "Microsoft.Data.Odbc.OdbcConnection"};
932 SetupExternalProvider(extp
);
933 UseParameters
= false;
934 UseSimpleReader
= false;
937 UseParameters
= false;
938 UseSimpleReader
= true;
942 extp
= new string[3] {
944 @"FirebirdSql.Data.Firebird, Version=1.6.3.0, Culture=neutral, PublicKeyToken=e1b4f92304d7b12f",
945 "FirebirdSql.Data.Firebird.FbConnection"};
946 SetupExternalProvider(extp
);
947 UseParameters
= false;
948 UseSimpleReader
= false;
952 extp
= new string[3] {
954 @"Npgsql, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7",
955 "Npgsql.NpgsqlConnection"};
956 SetupExternalProvider(extp
);
957 UseParameters
= false;
958 UseSimpleReader
= false;
961 Console
.WriteLine("Error: " + "Bad argument or Provider not supported.");
964 Console
.WriteLine("The default Provider is " + provider
);
965 if(provider
.Equals("LOADEXTPROVIDER")) {
966 Console
.WriteLine(" Assembly: " +
968 Console
.WriteLine(" Connection Class: " +
969 providerConnectionClass
);
973 Console
.WriteLine("Error: provider only has one parameter.");
976 // ChangeConnectionString - change the connection string variable
977 public void ChangeConnectionString(string entry
) {
979 if(entry
.Length
> 18)
980 connectionString
= entry
.Substring(18, entry
.Length
- 18);
982 connectionString
= "";
985 public void SetupOutputResultsFile(string[] parms
) {
986 if(parms
.Length
!= 2) {
987 Console
.WriteLine("Error: wrong number of parameters");
991 outputFilestream
= new StreamWriter(parms
[1]);
994 Console
.WriteLine("Error: Unable to setup output results file. " +
1000 public void SetupInputCommandsFile(string[] parms
) {
1001 if(parms
.Length
!= 2) {
1002 Console
.WriteLine("Error: wrong number of parameters");
1006 inputFilestream
= new StreamReader(parms
[1]);
1008 catch(Exception e
) {
1009 Console
.WriteLine("Error: Unable to setup input commmands file. " +
1015 public void LoadBufferFromFile(string[] parms
) {
1016 if(parms
.Length
!= 2) {
1017 Console
.WriteLine("Error: wrong number of parameters");
1020 string inFilename
= parms
[1];
1022 StreamReader sr
= new StreamReader( inFilename
);
1023 StringBuilder buffer
= new StringBuilder();
1026 while((NextLine
= sr
.ReadLine()) != null) {
1027 buffer
.Append(NextLine
);
1028 buffer
.Append("\n");
1031 buff
= buffer
.ToString();
1033 build
= new StringBuilder();
1036 catch(Exception e
) {
1037 Console
.WriteLine("Error: Unable to read file into SQL Buffer. " +
1042 public void SaveBufferToFile(string[] parms
) {
1043 if(parms
.Length
!= 2) {
1044 Console
.WriteLine("Error: wrong number of parameters");
1047 string outFilename
= parms
[1];
1049 StreamWriter sw
= new StreamWriter(outFilename
);
1053 catch(Exception e
) {
1054 Console
.WriteLine("Error: Could not save SQL Buffer to file." +
1059 public void SetUseParameters(string[] parms
) {
1060 if(parms
.Length
!= 2) {
1061 Console
.WriteLine("Error: wrong number of parameters");
1064 string parm
= parms
[1].ToUpper();
1065 if(parm
.Equals("TRUE"))
1066 UseParameters
= true;
1067 else if(parm
.Equals("FALSE"))
1068 UseParameters
= false;
1070 Console
.WriteLine("Error: invalid parameter.");
1074 public void SetUseSimpleReader(string[] parms
) {
1075 if(parms
.Length
!= 2) {
1076 Console
.WriteLine("Error: wrong number of parameters");
1079 string parm
= parms
[1].ToUpper();
1080 if(parm
.Equals("TRUE"))
1081 UseSimpleReader
= true;
1082 else if(parm
.Equals("FALSE"))
1083 UseSimpleReader
= false;
1085 Console
.WriteLine("Error: invalid parameter.");
1088 public void SetupSilentMode(string[] parms
) {
1089 if(parms
.Length
!= 2) {
1090 Console
.WriteLine("Error: wrong number of parameters");
1093 string parm
= parms
[1].ToUpper();
1094 if(parm
.Equals("TRUE"))
1096 else if(parm
.Equals("FALSE"))
1099 Console
.WriteLine("Error: invalid parameter.");
1102 public void SetInternalVariable(string[] parms
) {
1103 if(parms
.Length
< 2) {
1104 Console
.WriteLine("Error: wrong number of parameters.");
1107 string parm
= parms
[1];
1108 StringBuilder ps
= new StringBuilder();
1110 for(int i
= 2; i
< parms
.Length
; i
++)
1111 ps
.Append(parms
[i
]);
1113 internalVariables
[parm
] = ps
.ToString();
1116 public void UnSetInternalVariable(string[] parms
) {
1117 if(parms
.Length
!= 2) {
1118 Console
.WriteLine("Error: wrong number of parameters.");
1121 string parm
= parms
[1];
1124 internalVariables
.Remove(parm
);
1126 catch(Exception e
) {
1127 Console
.WriteLine("Error: internal variable does not exist: " +
1132 public void ShowInternalVariable(string[] parms
) {
1133 string internalVariableValue
= "";
1135 if(parms
.Length
!= 2) {
1136 Console
.WriteLine("Error: wrong number of parameters.");
1140 string parm
= parms
[1];
1142 if(GetInternalVariable(parm
, out internalVariableValue
) == true)
1143 Console
.WriteLine("Internal Variable - Name: " +
1144 parm
+ " Value: " + internalVariableValue
);
1147 public bool GetInternalVariable(string name
, out string sValue
) {
1149 bool valueReturned
= false;
1152 if(internalVariables
.ContainsKey(name
) == true) {
1153 sValue
= (string) internalVariables
[name
];
1154 valueReturned
= true;
1157 Console
.WriteLine("Error: internal variable does not exist.");
1160 catch(Exception e
) {
1161 Console
.WriteLine("Error: internal variable does not exist: "+
1164 return valueReturned
;
1167 public void SetupExternalProvider(string[] parms
) {
1168 if(parms
.Length
!= 3) {
1169 Console
.WriteLine("Error: Wrong number of parameters.");
1172 provider
= "LOADEXTPROVIDER";
1173 providerAssembly
= parms
[1];
1174 providerConnectionClass
= parms
[2];
1177 public bool LoadExternalProvider() {
1180 bool success
= false;
1182 // For example: for the MySQL provider in Mono.Data.MySql
1183 // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
1184 // \ConnectionString dbname=test
1186 // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
1192 Console
.WriteLine("Loading external provider...");
1193 Console
.Out
.Flush();
1195 Assembly ps
= Assembly
.Load(providerAssembly
);
1196 conType
= ps
.GetType(providerConnectionClass
);
1197 conn
= (IDbConnection
) Activator
.CreateInstance(conType
);
1200 Console
.WriteLine("External provider loaded.");
1201 Console
.Out
.Flush();
1202 UseParameters
= false;
1204 catch(FileNotFoundException f
) {
1205 msg
= "Error: unable to load the assembly of the provider: " +
1208 Console
.WriteLine(msg
);
1210 catch(Exception e
) {
1211 msg
= "Error: unable to load the assembly of the provider: " +
1214 Console
.WriteLine(msg
);
1219 // used for outputting message, but if silent is set,
1221 public void OutputLine(string line
) {
1226 // used for outputting the header columns of a result
1227 public void OutputHeader(string line
) {
1228 if(showHeader
== true)
1232 // OutputData() - used for outputting data
1233 // if an output filename is set, then the data will
1234 // go to a file; otherwise, it will go to the Console.
1235 public void OutputData(string line
) {
1236 if(outputFilestream
== null)
1237 Console
.WriteLine(line
);
1239 outputFilestream
.WriteLine(line
);
1242 // HandleCommand - handle SqlSharpCli commands entered
1243 public void HandleCommand(string entry
) {
1246 parms
= entry
.Split(new char[1] {' '}
);
1247 string userCmd
= parms
[0].ToUpper();
1251 ChangeProvider(parms
);
1253 case "\\CONNECTIONSTRING":
1254 ChangeConnectionString(entry
);
1256 case "\\LOADEXTPROVIDER":
1257 SetupExternalProvider(parms
);
1266 SetupSilentMode(parms
);
1272 // Execute SQL Commands or Queries
1274 Console
.WriteLine("Error: connection is not Open.");
1275 else if(conn
.State
== ConnectionState
.Closed
)
1276 Console
.WriteLine("Error: connection is not Open.");
1279 Console
.WriteLine("Error: SQL Buffer is empty.");
1281 buff
= build
.ToString();
1287 case "\\EXENONQUERY":
1289 Console
.WriteLine("Error: connection is not Open.");
1290 else if(conn
.State
== ConnectionState
.Closed
)
1291 Console
.WriteLine("Error: connection is not Open.");
1294 Console
.WriteLine("Error: SQL Buffer is empty.");
1296 buff
= build
.ToString();
1297 ExecuteSqlNonQuery(buff
);
1304 Console
.WriteLine("Error: connection is not Open.");
1305 else if(conn
.State
== ConnectionState
.Closed
)
1306 Console
.WriteLine("Error: connection is not Open.");
1309 Console
.WriteLine("Error: SQL Buffer is empty.");
1311 buff
= build
.ToString();
1312 ExecuteSqlScalar(buff
);
1318 // \exexml OUTPUT_FILENAME
1320 Console
.WriteLine("Error: connection is not Open.");
1321 else if(conn
.State
== ConnectionState
.Closed
)
1322 Console
.WriteLine("Error: connection is not Open.");
1325 Console
.WriteLine("Error: SQL Buffer is empty.");
1327 buff
= build
.ToString();
1328 ExecuteSqlXml(buff
, parms
);
1334 SetupInputCommandsFile(parms
);
1337 SetupOutputResultsFile(parms
);
1340 // Load file into SQL buffer: \load FILENAME
1341 LoadBufferFromFile(parms
);
1344 // Save SQL buffer to file: \save FILENAME
1345 SaveBufferToFile(parms
);
1353 // show the defaults for provider and connection strings
1363 // reset (clear) the query buffer
1367 // sets internal variable
1369 SetInternalVariable(parms
);
1372 // deletes internal variable
1374 UnSetInternalVariable(parms
);
1377 ShowInternalVariable(parms
);
1381 Console
.WriteLine("SQL Buffer is empty.");
1383 Console
.WriteLine("SQL Bufer:\n" + buff
);
1385 case "\\USEPARAMETERS":
1386 SetUseParameters(parms
);
1388 case "\\USESIMPLEREADER":
1389 SetUseSimpleReader(parms
);
1393 Console
.WriteLine("Error: Unknown user command.");
1398 public void DealWithArgs(string[] args
) {
1399 for(int a
= 0; a
< args
.Length
; a
++) {
1400 if(args
[a
].Substring(0,1).Equals("-")) {
1401 string arg
= args
[a
].ToUpper().Substring(1, args
[a
].Length
- 1);
1407 if(a
+ 1 >= args
.Length
)
1408 Console
.WriteLine("Error: Missing FILENAME for -f switch");
1410 inputFilename
= args
[a
+ 1];
1411 inputFilestream
= new StreamReader(inputFilename
);
1415 if(a
+ 1 >= args
.Length
)
1416 Console
.WriteLine("Error: Missing FILENAME for -o switch");
1418 outputFilename
= args
[a
+ 1];
1419 outputFilestream
= new StreamWriter(outputFilename
);
1423 Console
.WriteLine("Error: Unknow switch: " + args
[a
]);
1430 public string ReadSqlSharpCommand() {
1433 if(inputFilestream
== null) {
1434 Console
.Write("\nSQL# ");
1435 entry
= Console
.ReadLine();
1439 entry
= inputFilestream
.ReadLine();
1441 Console
.WriteLine("Executing SQL# Commands from file done.");
1444 catch(Exception e
) {
1445 Console
.WriteLine("Error: Reading command from file: " +
1448 Console
.Write("\nSQL# ");
1449 entry
= Console
.ReadLine();
1454 public void Run(string[] args
) {
1461 if(silent
== false) {
1462 Console
.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
1463 Console
.WriteLine("for Mono.Data. See http://www.go-mono.com/ for more details.\n");
1469 while(entry
.ToUpper().Equals("\\Q") == false &&
1470 entry
.ToUpper().Equals("\\QUIT") == false) {
1472 while((entry
= ReadSqlSharpCommand()) == "") {}
1475 if(entry
.Substring(0,1).Equals("\\")) {
1476 HandleCommand(entry
);
1478 else if(entry
.IndexOf(";") >= 0) {
1479 // most likely the end of SQL Command or Query found
1482 Console
.WriteLine("Error: connection is not Open.");
1483 else if(conn
.State
== ConnectionState
.Closed
)
1484 Console
.WriteLine("Error: connection is not Open.");
1487 build
= new StringBuilder();
1489 build
.Append(entry
);
1490 //build.Append("\n");
1491 buff
= build
.ToString();
1497 // most likely a part of a SQL Command or Query found
1498 // append this part of the SQL
1500 build
= new StringBuilder();
1502 build
.Append(entry
+ "\n");
1503 buff
= build
.ToString();
1507 if(outputFilestream
!= null)
1508 outputFilestream
.Close();
1512 public enum BindVariableCharacter
{
1513 Colon
, // ':' - named parameter - :name
1514 At
, // '@' - named parameter - @name
1515 QuestionMark
, // '?' - positioned parameter - ?
1516 SquareBrackets
// '[]' - delimited named parameter - [name]
1519 public class ParametersBuilder
{
1521 private BindVariableCharacter bindCharSetting
;
1522 private char bindChar
;
1523 private IDataParameterCollection parms
;
1525 private IDbCommand cmd
;
1527 private void SetBindCharacter() {
1528 switch(bindCharSetting
) {
1529 case BindVariableCharacter
.Colon
:
1532 case BindVariableCharacter
.At
:
1535 case BindVariableCharacter
.SquareBrackets
:
1538 case BindVariableCharacter
.QuestionMark
:
1544 public ParametersBuilder(IDbCommand command
, BindVariableCharacter bindVarChar
) {
1546 sql
= cmd
.CommandText
;
1547 parms
= cmd
.Parameters
;
1548 bindCharSetting
= bindVarChar
;
1552 public char ParameterMarkerCharacter
{
1558 public int ParseParameters() {
1562 IDataParameterCollection parms
= cmd
.Parameters
;
1564 char[] chars
= sql
.ToCharArray();
1565 bool bStringConstFound
= false;
1567 for(int i
= 0; i
< chars
.Length
; i
++) {
1568 if(chars
[i
] == '\'') {
1569 if(bStringConstFound
== true)
1570 bStringConstFound
= false;
1572 bStringConstFound
= true;
1574 else if(chars
[i
] == bindChar
&&
1575 bStringConstFound
== false) {
1576 if(bindChar
!= '?') {
1577 StringBuilder parm
= new StringBuilder();
1579 if(bindChar
.Equals('[')) {
1580 bool endingBracketFound
= false;
1581 while(i
<= chars
.Length
) {
1583 if(i
== chars
.Length
)
1584 ch
= ' '; // a space
1588 if(Char
.IsLetterOrDigit(ch
) || ch
== ' ') {
1591 else if (ch
== ']') {
1592 endingBracketFound
= true;
1593 string p
= parm
.ToString();
1598 else throw new Exception("SQL Parser Error: Invalid character in parameter name");
1602 if(endingBracketFound
== false)
1603 throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
1606 while(i
<= chars
.Length
) {
1608 if(i
== chars
.Length
)
1609 ch
= ' '; // a space
1613 if(Char
.IsLetterOrDigit(ch
)) {
1618 string p
= parm
.ToString();
1629 // placeholder paramaeter for ?
1630 string p
= numParms
.ToString();
1639 public void AddParameter (string p
) {
1640 Console
.WriteLine("Add Parameter: " + p
);
1641 if(parms
.Contains(p
) == false) {
1642 IDataParameter prm
= cmd
.CreateParameter();
1643 prm
.ParameterName
= p
;
1644 prm
.Direction
= ParameterDirection
.Input
;
1645 prm
.DbType
= DbType
.String
; // default
1646 prm
.Value
= ""; // default
1647 cmd
.Parameters
.Add(prm
);
1652 public class SqlSharpDriver
{
1653 public static void Main(string[] args
) {
1654 SqlSharpCli sqlCommandLineEngine
= new SqlSharpCli();
1655 sqlCommandLineEngine
.Run(args
);