Kaynağa Gözat

2002-05-27 Daniel Morgan <[email protected]>

	* System.Data.SqlClient/SqlCommand.cs: typo
	should be CommandBehavior.KeyInfo

	* Test/SqlSharpCli.cs: refactored and added a few more
	features.

svn path=/trunk/mcs/; revision=4961
Daniel Morgan 23 yıl önce
ebeveyn
işleme
51b401fe0f

+ 2 - 1
mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgSqlCommand.cs

@@ -860,7 +860,8 @@ namespace System.Data.SqlClient {
 					schemaRow["ColumnSize"] = PostgresLibrary.PQfsize (pgResult, i);
 					schemaRow["NumericPrecision"] = 0;
 					schemaRow["NumericScale"] = 0;
-					if((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.KeyInfo) {
+					// TODO: need to get KeyInfo
+					if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
 						bool IsUnique, IsKey;
 						GetKeyInfo(columnName, out IsUnique, out IsKey);
 					}

+ 2 - 1
mcs/class/Mono.Data.PostgreSqlClient/PgSqlCommand.cs

@@ -860,7 +860,8 @@ namespace System.Data.SqlClient {
 					schemaRow["ColumnSize"] = PostgresLibrary.PQfsize (pgResult, i);
 					schemaRow["NumericPrecision"] = 0;
 					schemaRow["NumericScale"] = 0;
-					if((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.KeyInfo) {
+					// TODO: need to get KeyInfo
+					if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
 						bool IsUnique, IsKey;
 						GetKeyInfo(columnName, out IsUnique, out IsKey);
 					}

+ 8 - 0
mcs/class/System.Data/ChangeLog

@@ -1,3 +1,11 @@
+2002-05-27  Daniel Morgan <[email protected]>
+
+	* System.Data.SqlClient/SqlCommand.cs: typo
+	should be CommandBehavior.KeyInfo
+	
+	* Test/SqlSharpCli.cs: refactored and added a few more
+	features.
+
 2002-05-27  Tim Coleman <[email protected]>
 	* list: update to compile properly (add missing
 	files and switch path delimiter from '\' to '/').

+ 2 - 1
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

@@ -860,7 +860,8 @@ namespace System.Data.SqlClient {
 					schemaRow["ColumnSize"] = PostgresLibrary.PQfsize (pgResult, i);
 					schemaRow["NumericPrecision"] = 0;
 					schemaRow["NumericScale"] = 0;
-					if((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.KeyInfo) {
+					// TODO: need to get KeyInfo
+					if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
 						bool IsUnique, IsKey;
 						GetKeyInfo(columnName, out IsUnique, out IsKey);
 					}

+ 369 - 148
mcs/class/System.Data/Test/SqlSharpCli.cs

@@ -13,6 +13,15 @@
 //                    For more information about Mono::, 
 //                    visit http://www.go-mono.com/
 //
+// To build SqlSharpCli.cs:
+// $ mcs SqlSharpCli.cs -r System.Data.dll
+//
+// To run:
+// $ mono SqlSharpCli.exe
+//
+// To run batch commands and get the output, do something like:
+// $ cat commands.txt | mono SqlSharpCli.exe > results.txt
+//
 // Author:
 //    Daniel Morgan <[email protected]>
 //
@@ -23,6 +32,7 @@ using System;
 using System.Data;
 using System.Data.Common;
 using System.Data.SqlClient;
+using System.IO;
 using System.Text;
 
 namespace Mono.Data.SqlSharp {
@@ -31,51 +41,86 @@ namespace Mono.Data.SqlSharp {
 	public class SqlSharpCli {
 	
 		private IDbConnection conn = null;
-		string provider = "POSTGRESCLIENT";
-		// string connectionString = "server=DANPC;database=pubs;uid=sa;pwd=freetds";
-		string connectionString = "host=localhost;dbname=test;user=postgres";
-
+		private string provider = "POSTGRESCLIENT";
+		private StringBuilder build = null; // SQL string to build
+		private string connectionString = 
+			"host=localhost;dbname=test;user=postgres";
+		private string inputFilename = "";
+		private string outputFilename = "";
+		private bool silent = false;
+		
+		// DisplayResult - used to Read() display a result set
+		//                   called by DisplayData()
 		public void DisplayResult(IDataReader reader, DataTable schemaTable) {
 
 			StringBuilder line = null;
-			string lineOut;
-
+			StringBuilder hdrUnderline = null;
+			
 			int spacing = 0;
 			int columnSize = 0;
+			int c;
 			
 			char spacingChar = ' '; // a space
+			char underlineChar = '='; // an equal sign
+
+			string dataType; // .NET Type
+			string dataTypeName; // native Database type
+			DataRow row; // schema row
+
 			line = new StringBuilder();
-			Console.WriteLine("Fields in Query Result: " + reader.FieldCount);
+			hdrUnderline = new StringBuilder();
+
+			Console.WriteLine("Fields in Query Result: " + 
+						reader.FieldCount);
+			Console.WriteLine();
 			
-			foreach(DataRow schemaRow in schemaTable.Rows) {
+			for(c = 0; c < schemaTable.Rows.Count; c++) {
+							
+				DataRow schemaRow = schemaTable.Rows[c];
 				string columnHeader = (string) schemaRow["ColumnName"];
 				int columnHeaderSize = columnHeader.Length;
+				
 				line.Append(columnHeader);
-				line.Append(" ");
+				hdrUnderline.Append(underlineChar, columnHeaderSize);
 					
 				// spacing
 				columnSize = (int) schemaRow["ColumnSize"];
+				dataType = (string) schemaRow["DataType"];
+				dataTypeName = reader.GetDataTypeName(c);
+				
+				// columnSize correction based on data type
+				if(dataType.Equals("System.Boolean")) {
+					columnSize = 5;
+				}
+				if(provider.Equals("POSTGRESCLIENT"))
+					if(dataTypeName.Equals("text"))				
+						columnSize = 32; // text will be truncated to 32
+
 				if(columnHeaderSize < columnSize) {
 					spacing = columnSize - columnHeaderSize;
 					line.Append(spacingChar, spacing);
+					hdrUnderline.Append(underlineChar, spacing);
 				}
-
+				line.Append(" ");
+				hdrUnderline.Append(" ");
 			}
-			lineOut = line.ToString();
-			Console.WriteLine(line);
+			Console.WriteLine(line.ToString());
 			line = null;
-			line = new StringBuilder();
-
+			
+			Console.WriteLine(hdrUnderline);
+			Console.WriteLine();
+			hdrUnderline = null;
+			
 			// DEBUG - need to know the columnSize
 			/*
+			line = new StringBuilder();
 			foreach(DataRow schemaRow in schemaTable.Rows) {
 				columnSize = (int) schemaRow["ColumnSize"];
 				line.Append(columnSize.ToString());
 				line.Append(" ");
 			}		
-			lineOut = line.ToString();
-			Console.WriteLine(line);
-			Console.WriteLine("");
+			Console.WriteLine(line.ToString());
+			Console.WriteLine();
 			line = null;
 			*/
 								
@@ -86,18 +131,26 @@ namespace Mono.Data.SqlSharp {
 				rows++;
 
 				line = new StringBuilder();
-				for(int c = 0; c < reader.FieldCount; c++) {
+				for(c = 0; c < reader.FieldCount; c++) {
 					int dataLen = 0;
 					string dataValue;
-					string dataType;	
-					DataRow row = schemaTable.Rows[c];
+					
+					row = schemaTable.Rows[c];
 					string colhdr = (string) row["ColumnName"];
 					columnSize = (int) row["ColumnSize"];
 					dataType = (string) row["DataType"];
+					dataTypeName = reader.GetDataTypeName(c);
+					
+					// certain types need to have the
+					// columnSize adjusted for display
+					// so the column will line up for each
+					// row and match the column header size
 					if(dataType.Equals("System.Boolean")) {
 						columnSize = 5;
 					}
-					int columnHeaderLen = colhdr.Length;
+					if(provider.Equals("POSTGRESCLIENT"))
+						if(dataTypeName.Equals("text"))				
+							columnSize = 32; // text will be truncated to 32
 												
 					if(reader.IsDBNull(c)) {
 						dataValue = "";
@@ -119,47 +172,69 @@ namespace Mono.Data.SqlSharp {
 						line.Append(spacingChar, spacing);
 					}
 					spacingChar = ' ';
-					if(columnSize < columnHeaderLen) {
-						spacing = columnHeaderLen - columnSize;
+					if(columnSize < colhdr.Length) {
+						spacing = colhdr.Length - columnSize;
 						line.Append(spacingChar, spacing);
 					}
 						
 				}
-				lineOut = line.ToString();
-				Console.WriteLine(lineOut);
+				Console.WriteLine(line.ToString());
 				line = null;
 			}
 			Console.WriteLine("\nRows retrieved: " + rows);
 		}
 
+		// DisplayData - used to display any Result Sets
+		//                 from execution of SQL SELECT Query or Queries
+		//                 called by DisplayData. 
+		//                 ExecuteSql() only calls this function
+		//                 for a Query, it does not get
+		//                 for a Command.
 		public void DisplayData(IDataReader reader) {
 
-			DataTable schemaTable;
+			DataTable schemaTable = null;
 			int ResultSet = 0;
 
 			Console.WriteLine("Display any result sets...");
 
 			do {
+				// by Default, SqlDataReader has the 
+				// first Result set if any
+
 				ResultSet++;
 				Console.WriteLine("Display the result set " + ResultSet);
 				
 				schemaTable = reader.GetSchemaTable();
-				if(reader.RecordsAffected >= 0)
+				
+				if(reader.RecordsAffected >= 0) {
+					// SQL Command (INSERT, UPDATE, or DELETE)
+					// RecordsAffected >= 0
 					Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
-				else if(schemaTable == null)
-					Console.WriteLine("SQL Command executed.");
+				}
+				else if(schemaTable == null) {
+					// SQL Command (not INSERT, UPDATE, nor DELETE)
+					// RecordsAffected -1 and DataTable has a null reference
+					Console.WriteLine("SQL Command Executed.");
+				}
 				else {
+					// SQL Query (SELECT)
+					// RecordsAffected -1 and DataTable has a reference
 					DisplayResult(reader, schemaTable);
 				}
+
+			// get next result set (if anymore is left)
 			} while(reader.NextResult());
 		}
 
-		public void RunStatement(string sql, string provider) {
+		// ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
+		public void ExecuteSql(string sql) {
+			
 			Console.WriteLine("Execute SQL: " + sql);
 
 			IDbCommand cmd = null;
 			IDataReader reader = null;
 
+			// create a Command object based on the provider
 			switch(provider) {
 			case "POSTGRESCLIENT":
 				cmd = new SqlCommand();
@@ -168,24 +243,35 @@ namespace Mono.Data.SqlSharp {
 				Console.WriteLine("Error: PostgreSQL is only supported, and it through SqlClient.");
 				return;
 			}
+
+			// set command properties
 			cmd.CommandType = CommandType.Text;
 			cmd.CommandText = sql;
 			cmd.Connection = conn;
+
 			try {
 				reader = cmd.ExecuteReader();
-				Console.WriteLine("Executed okay.");
 				DisplayData(reader);
 				reader.Close();
-				reader = null;
-				cmd = null;
+				//reader = null;
+				//cmd.Dispose();
+				//cmd = null;
 			}
 			catch(Exception e) {
 				Console.WriteLine("Exception Caught Executing SQL: " + e);
-				cmd = null;
+				//if(reader != null) {
+				//	if(reader.IsClosed == false)
+				//		reader.Close();
+				//	reader = null;
+				//}
+				// cmd.Dispose();
+				//cmd = null;
 			}
 		}
 
+		// ShowHelp - show the help - command a user can enter
 		public void ShowHelp() {
+			Console.WriteLine("");
 			Console.WriteLine(@"Type:  \Q to quit");
 			Console.WriteLine(@"       \ConnectionString to set the ConnectionString");
 			Console.WriteLine(@"       \Provider to set the Provider:");
@@ -194,129 +280,271 @@ namespace Mono.Data.SqlSharp {
 			Console.WriteLine(@"       \Open to open the connection");
 			Console.WriteLine(@"       \Close to close the connection");
 			Console.WriteLine(@"       \Execute to execute SQL command(s)/queries(s)");
+			Console.WriteLine(@"       \f FILENAME to read a batch of commands from");
+			Console.WriteLine(@"       \o FILENAME to read a batch of commands from");
 			Console.WriteLine(@"       \h to show this help.");
-			Console.WriteLine("\nThe default Provider is " + provider);
-			Console.WriteLine("\nThe default ConnectionString is: ");
+			Console.WriteLine(@"       \s {TRUE, FALSE} to silent messages.");
+			Console.WriteLine();
+		}
+
+		// ShowDefaults - show defaults for connection variables
+		public void ShowDefaults() {
+			Console.WriteLine();
+			Console.WriteLine("The default Provider is " + provider);
+			Console.WriteLine();
+			Console.WriteLine("The default ConnectionString is: ");
 			Console.WriteLine("    \"" + connectionString + "\"");
 			Console.WriteLine();
 		}
-		
-		public void Run(string[] args) {
-			string entry = "";
-			string[] parms;
-			StringBuilder build = null;
 
-			Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
-			Console.WriteLine("for Mono.Data.  See http://www.go-mono.com/ for more details.\n");
-			ShowHelp();
+		// OpenDataSource - open connection to the data source
+		public void OpenDataSource() {
 			
-			while(entry.ToUpper().Equals("\\Q") == false) {
-				
-				Console.Write("\nSQL# ");
-				entry = Console.ReadLine();
+			Console.WriteLine("Attempt to Open...");
 
-				Console.WriteLine("Entered: " + entry);
-				
-				if(entry.Substring(0,1).Equals("\\")) {
-					// maybe a SQL# Command was found
-					parms = entry.Split(new char[1] {' '});
-					Console.WriteLine("Parms: " + parms.Length); 
-					string userCmd = parms[0].ToUpper();
-					switch(userCmd) {
-					case "\\PROVIDER":
-						if(parms.Length == 2) {
-							string parm = parms[1].ToUpper();
-							switch(parm) {
-							case "OLEDB":
-							case "ORACLECLIENT":
-								Console.WriteLine("Error: Provider not currently supported.");
-								break;
-							case "SQLCLIENT":
-								provider = "POSTGRESCLIENT";
-								Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
-								break;
-							case "POSTGRESCLIENT":
-								provider = parm;
-								break;
-							default:
-								Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
-								break;
-							}
-							Console.WriteLine("Provider: " + provider);
-						}
-						else
-							Console.WriteLine("Error: provider only has one parameter.");
+			switch(provider) {
+			case "POSTGRESCLIENT":
+				conn = new SqlConnection();
+				break;
+			default:
+				Console.WriteLine("Error: Currently, PostgreSQL is the only provider supported, and it through SqlClient.");
+				break;
+			}
 
+			conn.ConnectionString = connectionString;
+			
+			try {
+				conn.Open();
+				if(conn.State == ConnectionState.Open)
+					Console.WriteLine("Open was successfully.");
+			}
+			catch(Exception e) {
+				Console.WriteLine("Exception Caught Opening. " + e);
+				conn = null;
+			}
+		}
+
+		// CloseDataSource - close the connection to the data source
+		public void CloseDataSource() {
+			Console.WriteLine("Attempt to Close...");
+
+			try {
+				conn.Close();
+				Console.WriteLine("Close was successfull.");
+			}
+			catch(Exception e) {
+				Console.WriteLine("Exeception Caught Closing. " + e);
+			}
+			conn = null;
+		}
+
+		// ChangeProvider - change the provider string variable
+		public void ChangeProvider(string[] parms) {
+
+			if(parms.Length == 2) {
+				string parm = parms[1].ToUpper();
+				switch(parm) {
+				case "OLEDB":
+				case "ORACLECLIENT":
+					Console.WriteLine("Error: Provider not currently supported.");
+					break;
+				case "SQLCLIENT":
+					provider = "POSTGRESCLIENT";
+					Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
+					break;
+				case "POSTGRESCLIENT":
+					provider = parm;
+					break;
+				default:
+					Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
+					break;
+				}
+				Console.WriteLine("Provider: " + provider);
+			}
+			else
+				Console.WriteLine("Error: provider only has one parameter.");
+		}
+
+		// ChangeConnectionString - change the connection string variable
+		public void ChangeConnectionString(string entry) {
+			
+			if(entry.Length > 18)
+				connectionString = entry.Substring(18, entry.Length - 18);
+			else
+				connectionString = "";
+		}
+
+		public void SetupInputFile(string[] parms) {
+			if(parms.Length >= 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+				return;
+			}
+			inputFilename = parms[1];
+			// TODO:
+			// open input file
+			// while each line, do the SqlSharpCli command or SQL
+			// close input file
+		}
+
+		public void SetupOutputFile(string[] parms) {
+			if(parms.Length == 1) {
+				outputFilename = "";
+				// TODO: close the output file
+			}
+			else if(parms.Length > 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+			}
+			else {
+				outputFilename = parms[1];
+				// TODO: open the output file
+			}
+		}
+
+		public void SetupSilentMode(string[] parms) {
+			if(parms.Length != 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+				return;
+			}
+			string parm = parms[1].ToUpper();
+			if(parm.Equals("TRUE"))
+				silent = true;
+			else if(parm.Equals("FALSE"))
+				silent = false;
+			else
+				Console.WriteLine("Error: invalid parameter.");
+		}
+
+		public void OutputLine(string line) {
+			if(silent == false)
+				Console.WriteLine(line);
+		}
+
+		public void ExecuteBatch() {
+			// TODO:
+			Console.WriteLine("Error: Execution of Batch Commands not implemented yet");
+		}
+
+		// HandleCommand - handle SqlSharpCli commands entered
+		public void HandleCommand(string entry) {
+			
+			string[] parms;
+			
+			// maybe a SQL# Command was found
+			parms = entry.Split(new char[1] {' '});
+			string userCmd = parms[0].ToUpper();
+
+			switch(userCmd) {
+			case "\\PROVIDER":
+				ChangeProvider(parms);
+				break;
+			case "\\CONNECTIONSTRING":
+				ChangeConnectionString(entry);
+				break;
+			case "\\OPEN":
+				OpenDataSource();
+				break;
+			case "\\CLOSE":
+				CloseDataSource();
+				break;
+			case "\\S":
+				SetupSilentMode(parms);
+				break;
+			case "\\E":
+			case "\\EXECUTE":
+				// Execute SQL Commands or Queries
+				if(conn == null)
+					Console.WriteLine("Error: connection is not Open.");
+				else if(conn.State == ConnectionState.Closed)
+					Console.WriteLine("Error: connection is not Open.");
+				else {
+					if(build == null)
+						Console.WriteLine("Error: SQL Buffer is empty.");
+					else {
+						ExecuteSql(build.ToString());
+					}
+					build = null;
+				}
+				break;
+			case "\\F":
+				// Batch Input File: \f FILENAME
+				SetupInputFile(parms);
+				ExecuteBatch();
+				break;
+			case "\\O":
+				// Batch Output File: \o FILENAME
+				SetupOutputFile(parms);
+				break;
+			case "\\H":
+			case "\\HELP":
+				// Help
+				ShowHelp();
+				break;
+			case "\\Q": 
+			case "\\QUIT":
+				// Quit
+				break;
+			default:
+				// Error
+				Console.WriteLine("Error: Unknown user command.");
+				break;
+			}
+		}
+
+		public void DealWithArgs(string[] args) {
+			for(int a = 0; a < args.Length; a++) {
+				if(args[a].Substring(0,1).Equals("-")) {
+					string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
+					switch(arg) {
+					case "S":
+						silent = true;
 						break;
-					case "\\CONNECTIONSTRING":
-						if(entry.Length > 18)
-							connectionString = entry.Substring(18, entry.Length - 18);
-						else
-							connectionString = "";
-						Console.WriteLine("ConnectionString: " + connectionString);
-						Console.WriteLine("Lenght of ConnectionString: " + connectionString.Length);
-						break;
-					case "\\OPEN":
-						Console.WriteLine("Attempt to Open...");
-						switch(provider) {
-						case "POSTGRESCLIENT":
-							conn = new SqlConnection();
-							break;
-						default:
-							Console.WriteLine("Error: Currently, PostgreSQL is the only provider supported, and it through SqlClient.");
-							break;
-						}
-						conn.ConnectionString = connectionString;
-						try {
-							conn.Open();
-						}
-						catch(Exception e) {
-							Console.WriteLine("Exception Caught Opening. " + e);
-							conn = null;
-						}
-						if(conn.State == ConnectionState.Open)
-							Console.WriteLine("Assuming Open was successfully.");
-						break;
-					case "\\CLOSE":
-						Console.WriteLine("Attempt to Close...");
-						bool bCloseError = false;
-						try {
-							conn.Close();
-						}
-						catch(Exception e) {
-							Console.WriteLine("Exeception Caught Closing. " + e);
-							bCloseError = true;
-						}
-						if(bCloseError == false)
-							Console.WriteLine("Assuming Close was successfull.");
-						break;
-					case "\\EXECUTE":
-						if(conn == null)
-							Console.WriteLine("Error: connection is not Open.");
-						else if(conn.State == ConnectionState.Closed)
-							Console.WriteLine("Error: connection is not Open.");
+					case "F":		
+						if(a + 1 >= args.Length)
+							Console.WriteLine("Error: Missing FILENAME for -f switch");
 						else {
-							if(build == null)
-								Console.WriteLine("Error: SQL Buffer is empty.");
-							else {
-								string builtSQL = build.ToString();
-								Console.WriteLine("SQL: " + builtSQL);
-
-								RunStatement(builtSQL, provider);
-							}
-							build = null;
+							inputFilename = args[a + 1];
+							ExecuteBatch();
 						}
 						break;
-					case "\\H":
-						ShowHelp();
-						break;
-					case "\\Q":
+					case "O":
+						if(a + 1 >= args.Length)
+							Console.WriteLine("Error: Missing FILENAME for -o switch");
+						else
+							outputFilename = args[a + 1];
 						break;
 					default:
-						Console.WriteLine("Error: Unknown user command.");
+						Console.WriteLine("Error: Unknow switch: " + args[a]);
 						break;
 					}
+				}
+			}
+		}
+		
+		public void Run(string[] args) {
+
+			DealWithArgs(args);
+
+			string entry = "";
+			build = null;
+
+			if(silent == false) {
+				Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
+				Console.WriteLine("for Mono.Data.  See http://www.go-mono.com/ for more details.\n");
+						
+				ShowHelp();
+				ShowDefaults();
+			}
+			
+			while(entry.ToUpper().Equals("\\Q") == false &&
+				entry.ToUpper().Equals("\\QUIT") == false) {
 				
+				Console.Write("\nSQL# ");
+				entry = Console.ReadLine();
+
+				Console.WriteLine("Entered: " + entry);
+				
+				if(entry.Substring(0,1).Equals("\\")) {
+					HandleCommand(entry);
 				}
 				else if(entry.IndexOf(";") >= 0) {
 					// most likely the end of SQL Command or Query found
@@ -326,17 +554,11 @@ namespace Mono.Data.SqlSharp {
 					else if(conn.State == ConnectionState.Closed)
 						Console.WriteLine("Error: connection is not Open.");
 					else {
-						Console.WriteLine("if build == null");
 						if(build == null) {
-							Console.WriteLine("build is null, do new");
 							build = new StringBuilder();
 						}
-						Console.WriteLine("append entry");
 						build.Append(entry);
-						Console.WriteLine("build: " + build.ToString());
-						Console.WriteLine("RunStatement");
-						RunStatement(build.ToString(), provider);
-				
+						ExecuteSql(build.ToString());
 						build = null;
 					}
 				}
@@ -347,7 +569,6 @@ namespace Mono.Data.SqlSharp {
 						build = new StringBuilder();
 					}
 					build.Append(entry + " ");
-					Console.WriteLine("build: " + build.ToString());
 				}
 			}			
 		}

+ 369 - 148
mcs/tools/SqlSharp/SqlSharpCli.cs

@@ -13,6 +13,15 @@
 //                    For more information about Mono::, 
 //                    visit http://www.go-mono.com/
 //
+// To build SqlSharpCli.cs:
+// $ mcs SqlSharpCli.cs -r System.Data.dll
+//
+// To run:
+// $ mono SqlSharpCli.exe
+//
+// To run batch commands and get the output, do something like:
+// $ cat commands.txt | mono SqlSharpCli.exe > results.txt
+//
 // Author:
 //    Daniel Morgan <[email protected]>
 //
@@ -23,6 +32,7 @@ using System;
 using System.Data;
 using System.Data.Common;
 using System.Data.SqlClient;
+using System.IO;
 using System.Text;
 
 namespace Mono.Data.SqlSharp {
@@ -31,51 +41,86 @@ namespace Mono.Data.SqlSharp {
 	public class SqlSharpCli {
 	
 		private IDbConnection conn = null;
-		string provider = "POSTGRESCLIENT";
-		// string connectionString = "server=DANPC;database=pubs;uid=sa;pwd=freetds";
-		string connectionString = "host=localhost;dbname=test;user=postgres";
-
+		private string provider = "POSTGRESCLIENT";
+		private StringBuilder build = null; // SQL string to build
+		private string connectionString = 
+			"host=localhost;dbname=test;user=postgres";
+		private string inputFilename = "";
+		private string outputFilename = "";
+		private bool silent = false;
+		
+		// DisplayResult - used to Read() display a result set
+		//                   called by DisplayData()
 		public void DisplayResult(IDataReader reader, DataTable schemaTable) {
 
 			StringBuilder line = null;
-			string lineOut;
-
+			StringBuilder hdrUnderline = null;
+			
 			int spacing = 0;
 			int columnSize = 0;
+			int c;
 			
 			char spacingChar = ' '; // a space
+			char underlineChar = '='; // an equal sign
+
+			string dataType; // .NET Type
+			string dataTypeName; // native Database type
+			DataRow row; // schema row
+
 			line = new StringBuilder();
-			Console.WriteLine("Fields in Query Result: " + reader.FieldCount);
+			hdrUnderline = new StringBuilder();
+
+			Console.WriteLine("Fields in Query Result: " + 
+						reader.FieldCount);
+			Console.WriteLine();
 			
-			foreach(DataRow schemaRow in schemaTable.Rows) {
+			for(c = 0; c < schemaTable.Rows.Count; c++) {
+							
+				DataRow schemaRow = schemaTable.Rows[c];
 				string columnHeader = (string) schemaRow["ColumnName"];
 				int columnHeaderSize = columnHeader.Length;
+				
 				line.Append(columnHeader);
-				line.Append(" ");
+				hdrUnderline.Append(underlineChar, columnHeaderSize);
 					
 				// spacing
 				columnSize = (int) schemaRow["ColumnSize"];
+				dataType = (string) schemaRow["DataType"];
+				dataTypeName = reader.GetDataTypeName(c);
+				
+				// columnSize correction based on data type
+				if(dataType.Equals("System.Boolean")) {
+					columnSize = 5;
+				}
+				if(provider.Equals("POSTGRESCLIENT"))
+					if(dataTypeName.Equals("text"))				
+						columnSize = 32; // text will be truncated to 32
+
 				if(columnHeaderSize < columnSize) {
 					spacing = columnSize - columnHeaderSize;
 					line.Append(spacingChar, spacing);
+					hdrUnderline.Append(underlineChar, spacing);
 				}
-
+				line.Append(" ");
+				hdrUnderline.Append(" ");
 			}
-			lineOut = line.ToString();
-			Console.WriteLine(line);
+			Console.WriteLine(line.ToString());
 			line = null;
-			line = new StringBuilder();
-
+			
+			Console.WriteLine(hdrUnderline);
+			Console.WriteLine();
+			hdrUnderline = null;
+			
 			// DEBUG - need to know the columnSize
 			/*
+			line = new StringBuilder();
 			foreach(DataRow schemaRow in schemaTable.Rows) {
 				columnSize = (int) schemaRow["ColumnSize"];
 				line.Append(columnSize.ToString());
 				line.Append(" ");
 			}		
-			lineOut = line.ToString();
-			Console.WriteLine(line);
-			Console.WriteLine("");
+			Console.WriteLine(line.ToString());
+			Console.WriteLine();
 			line = null;
 			*/
 								
@@ -86,18 +131,26 @@ namespace Mono.Data.SqlSharp {
 				rows++;
 
 				line = new StringBuilder();
-				for(int c = 0; c < reader.FieldCount; c++) {
+				for(c = 0; c < reader.FieldCount; c++) {
 					int dataLen = 0;
 					string dataValue;
-					string dataType;	
-					DataRow row = schemaTable.Rows[c];
+					
+					row = schemaTable.Rows[c];
 					string colhdr = (string) row["ColumnName"];
 					columnSize = (int) row["ColumnSize"];
 					dataType = (string) row["DataType"];
+					dataTypeName = reader.GetDataTypeName(c);
+					
+					// certain types need to have the
+					// columnSize adjusted for display
+					// so the column will line up for each
+					// row and match the column header size
 					if(dataType.Equals("System.Boolean")) {
 						columnSize = 5;
 					}
-					int columnHeaderLen = colhdr.Length;
+					if(provider.Equals("POSTGRESCLIENT"))
+						if(dataTypeName.Equals("text"))				
+							columnSize = 32; // text will be truncated to 32
 												
 					if(reader.IsDBNull(c)) {
 						dataValue = "";
@@ -119,47 +172,69 @@ namespace Mono.Data.SqlSharp {
 						line.Append(spacingChar, spacing);
 					}
 					spacingChar = ' ';
-					if(columnSize < columnHeaderLen) {
-						spacing = columnHeaderLen - columnSize;
+					if(columnSize < colhdr.Length) {
+						spacing = colhdr.Length - columnSize;
 						line.Append(spacingChar, spacing);
 					}
 						
 				}
-				lineOut = line.ToString();
-				Console.WriteLine(lineOut);
+				Console.WriteLine(line.ToString());
 				line = null;
 			}
 			Console.WriteLine("\nRows retrieved: " + rows);
 		}
 
+		// DisplayData - used to display any Result Sets
+		//                 from execution of SQL SELECT Query or Queries
+		//                 called by DisplayData. 
+		//                 ExecuteSql() only calls this function
+		//                 for a Query, it does not get
+		//                 for a Command.
 		public void DisplayData(IDataReader reader) {
 
-			DataTable schemaTable;
+			DataTable schemaTable = null;
 			int ResultSet = 0;
 
 			Console.WriteLine("Display any result sets...");
 
 			do {
+				// by Default, SqlDataReader has the 
+				// first Result set if any
+
 				ResultSet++;
 				Console.WriteLine("Display the result set " + ResultSet);
 				
 				schemaTable = reader.GetSchemaTable();
-				if(reader.RecordsAffected >= 0)
+				
+				if(reader.RecordsAffected >= 0) {
+					// SQL Command (INSERT, UPDATE, or DELETE)
+					// RecordsAffected >= 0
 					Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
-				else if(schemaTable == null)
-					Console.WriteLine("SQL Command executed.");
+				}
+				else if(schemaTable == null) {
+					// SQL Command (not INSERT, UPDATE, nor DELETE)
+					// RecordsAffected -1 and DataTable has a null reference
+					Console.WriteLine("SQL Command Executed.");
+				}
 				else {
+					// SQL Query (SELECT)
+					// RecordsAffected -1 and DataTable has a reference
 					DisplayResult(reader, schemaTable);
 				}
+
+			// get next result set (if anymore is left)
 			} while(reader.NextResult());
 		}
 
-		public void RunStatement(string sql, string provider) {
+		// ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
+		public void ExecuteSql(string sql) {
+			
 			Console.WriteLine("Execute SQL: " + sql);
 
 			IDbCommand cmd = null;
 			IDataReader reader = null;
 
+			// create a Command object based on the provider
 			switch(provider) {
 			case "POSTGRESCLIENT":
 				cmd = new SqlCommand();
@@ -168,24 +243,35 @@ namespace Mono.Data.SqlSharp {
 				Console.WriteLine("Error: PostgreSQL is only supported, and it through SqlClient.");
 				return;
 			}
+
+			// set command properties
 			cmd.CommandType = CommandType.Text;
 			cmd.CommandText = sql;
 			cmd.Connection = conn;
+
 			try {
 				reader = cmd.ExecuteReader();
-				Console.WriteLine("Executed okay.");
 				DisplayData(reader);
 				reader.Close();
-				reader = null;
-				cmd = null;
+				//reader = null;
+				//cmd.Dispose();
+				//cmd = null;
 			}
 			catch(Exception e) {
 				Console.WriteLine("Exception Caught Executing SQL: " + e);
-				cmd = null;
+				//if(reader != null) {
+				//	if(reader.IsClosed == false)
+				//		reader.Close();
+				//	reader = null;
+				//}
+				// cmd.Dispose();
+				//cmd = null;
 			}
 		}
 
+		// ShowHelp - show the help - command a user can enter
 		public void ShowHelp() {
+			Console.WriteLine("");
 			Console.WriteLine(@"Type:  \Q to quit");
 			Console.WriteLine(@"       \ConnectionString to set the ConnectionString");
 			Console.WriteLine(@"       \Provider to set the Provider:");
@@ -194,129 +280,271 @@ namespace Mono.Data.SqlSharp {
 			Console.WriteLine(@"       \Open to open the connection");
 			Console.WriteLine(@"       \Close to close the connection");
 			Console.WriteLine(@"       \Execute to execute SQL command(s)/queries(s)");
+			Console.WriteLine(@"       \f FILENAME to read a batch of commands from");
+			Console.WriteLine(@"       \o FILENAME to read a batch of commands from");
 			Console.WriteLine(@"       \h to show this help.");
-			Console.WriteLine("\nThe default Provider is " + provider);
-			Console.WriteLine("\nThe default ConnectionString is: ");
+			Console.WriteLine(@"       \s {TRUE, FALSE} to silent messages.");
+			Console.WriteLine();
+		}
+
+		// ShowDefaults - show defaults for connection variables
+		public void ShowDefaults() {
+			Console.WriteLine();
+			Console.WriteLine("The default Provider is " + provider);
+			Console.WriteLine();
+			Console.WriteLine("The default ConnectionString is: ");
 			Console.WriteLine("    \"" + connectionString + "\"");
 			Console.WriteLine();
 		}
-		
-		public void Run(string[] args) {
-			string entry = "";
-			string[] parms;
-			StringBuilder build = null;
 
-			Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
-			Console.WriteLine("for Mono.Data.  See http://www.go-mono.com/ for more details.\n");
-			ShowHelp();
+		// OpenDataSource - open connection to the data source
+		public void OpenDataSource() {
 			
-			while(entry.ToUpper().Equals("\\Q") == false) {
-				
-				Console.Write("\nSQL# ");
-				entry = Console.ReadLine();
+			Console.WriteLine("Attempt to Open...");
 
-				Console.WriteLine("Entered: " + entry);
-				
-				if(entry.Substring(0,1).Equals("\\")) {
-					// maybe a SQL# Command was found
-					parms = entry.Split(new char[1] {' '});
-					Console.WriteLine("Parms: " + parms.Length); 
-					string userCmd = parms[0].ToUpper();
-					switch(userCmd) {
-					case "\\PROVIDER":
-						if(parms.Length == 2) {
-							string parm = parms[1].ToUpper();
-							switch(parm) {
-							case "OLEDB":
-							case "ORACLECLIENT":
-								Console.WriteLine("Error: Provider not currently supported.");
-								break;
-							case "SQLCLIENT":
-								provider = "POSTGRESCLIENT";
-								Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
-								break;
-							case "POSTGRESCLIENT":
-								provider = parm;
-								break;
-							default:
-								Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
-								break;
-							}
-							Console.WriteLine("Provider: " + provider);
-						}
-						else
-							Console.WriteLine("Error: provider only has one parameter.");
+			switch(provider) {
+			case "POSTGRESCLIENT":
+				conn = new SqlConnection();
+				break;
+			default:
+				Console.WriteLine("Error: Currently, PostgreSQL is the only provider supported, and it through SqlClient.");
+				break;
+			}
 
+			conn.ConnectionString = connectionString;
+			
+			try {
+				conn.Open();
+				if(conn.State == ConnectionState.Open)
+					Console.WriteLine("Open was successfully.");
+			}
+			catch(Exception e) {
+				Console.WriteLine("Exception Caught Opening. " + e);
+				conn = null;
+			}
+		}
+
+		// CloseDataSource - close the connection to the data source
+		public void CloseDataSource() {
+			Console.WriteLine("Attempt to Close...");
+
+			try {
+				conn.Close();
+				Console.WriteLine("Close was successfull.");
+			}
+			catch(Exception e) {
+				Console.WriteLine("Exeception Caught Closing. " + e);
+			}
+			conn = null;
+		}
+
+		// ChangeProvider - change the provider string variable
+		public void ChangeProvider(string[] parms) {
+
+			if(parms.Length == 2) {
+				string parm = parms[1].ToUpper();
+				switch(parm) {
+				case "OLEDB":
+				case "ORACLECLIENT":
+					Console.WriteLine("Error: Provider not currently supported.");
+					break;
+				case "SQLCLIENT":
+					provider = "POSTGRESCLIENT";
+					Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
+					break;
+				case "POSTGRESCLIENT":
+					provider = parm;
+					break;
+				default:
+					Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
+					break;
+				}
+				Console.WriteLine("Provider: " + provider);
+			}
+			else
+				Console.WriteLine("Error: provider only has one parameter.");
+		}
+
+		// ChangeConnectionString - change the connection string variable
+		public void ChangeConnectionString(string entry) {
+			
+			if(entry.Length > 18)
+				connectionString = entry.Substring(18, entry.Length - 18);
+			else
+				connectionString = "";
+		}
+
+		public void SetupInputFile(string[] parms) {
+			if(parms.Length >= 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+				return;
+			}
+			inputFilename = parms[1];
+			// TODO:
+			// open input file
+			// while each line, do the SqlSharpCli command or SQL
+			// close input file
+		}
+
+		public void SetupOutputFile(string[] parms) {
+			if(parms.Length == 1) {
+				outputFilename = "";
+				// TODO: close the output file
+			}
+			else if(parms.Length > 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+			}
+			else {
+				outputFilename = parms[1];
+				// TODO: open the output file
+			}
+		}
+
+		public void SetupSilentMode(string[] parms) {
+			if(parms.Length != 2) {
+				Console.WriteLine("Error: wrong number of parameters");
+				return;
+			}
+			string parm = parms[1].ToUpper();
+			if(parm.Equals("TRUE"))
+				silent = true;
+			else if(parm.Equals("FALSE"))
+				silent = false;
+			else
+				Console.WriteLine("Error: invalid parameter.");
+		}
+
+		public void OutputLine(string line) {
+			if(silent == false)
+				Console.WriteLine(line);
+		}
+
+		public void ExecuteBatch() {
+			// TODO:
+			Console.WriteLine("Error: Execution of Batch Commands not implemented yet");
+		}
+
+		// HandleCommand - handle SqlSharpCli commands entered
+		public void HandleCommand(string entry) {
+			
+			string[] parms;
+			
+			// maybe a SQL# Command was found
+			parms = entry.Split(new char[1] {' '});
+			string userCmd = parms[0].ToUpper();
+
+			switch(userCmd) {
+			case "\\PROVIDER":
+				ChangeProvider(parms);
+				break;
+			case "\\CONNECTIONSTRING":
+				ChangeConnectionString(entry);
+				break;
+			case "\\OPEN":
+				OpenDataSource();
+				break;
+			case "\\CLOSE":
+				CloseDataSource();
+				break;
+			case "\\S":
+				SetupSilentMode(parms);
+				break;
+			case "\\E":
+			case "\\EXECUTE":
+				// Execute SQL Commands or Queries
+				if(conn == null)
+					Console.WriteLine("Error: connection is not Open.");
+				else if(conn.State == ConnectionState.Closed)
+					Console.WriteLine("Error: connection is not Open.");
+				else {
+					if(build == null)
+						Console.WriteLine("Error: SQL Buffer is empty.");
+					else {
+						ExecuteSql(build.ToString());
+					}
+					build = null;
+				}
+				break;
+			case "\\F":
+				// Batch Input File: \f FILENAME
+				SetupInputFile(parms);
+				ExecuteBatch();
+				break;
+			case "\\O":
+				// Batch Output File: \o FILENAME
+				SetupOutputFile(parms);
+				break;
+			case "\\H":
+			case "\\HELP":
+				// Help
+				ShowHelp();
+				break;
+			case "\\Q": 
+			case "\\QUIT":
+				// Quit
+				break;
+			default:
+				// Error
+				Console.WriteLine("Error: Unknown user command.");
+				break;
+			}
+		}
+
+		public void DealWithArgs(string[] args) {
+			for(int a = 0; a < args.Length; a++) {
+				if(args[a].Substring(0,1).Equals("-")) {
+					string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
+					switch(arg) {
+					case "S":
+						silent = true;
 						break;
-					case "\\CONNECTIONSTRING":
-						if(entry.Length > 18)
-							connectionString = entry.Substring(18, entry.Length - 18);
-						else
-							connectionString = "";
-						Console.WriteLine("ConnectionString: " + connectionString);
-						Console.WriteLine("Lenght of ConnectionString: " + connectionString.Length);
-						break;
-					case "\\OPEN":
-						Console.WriteLine("Attempt to Open...");
-						switch(provider) {
-						case "POSTGRESCLIENT":
-							conn = new SqlConnection();
-							break;
-						default:
-							Console.WriteLine("Error: Currently, PostgreSQL is the only provider supported, and it through SqlClient.");
-							break;
-						}
-						conn.ConnectionString = connectionString;
-						try {
-							conn.Open();
-						}
-						catch(Exception e) {
-							Console.WriteLine("Exception Caught Opening. " + e);
-							conn = null;
-						}
-						if(conn.State == ConnectionState.Open)
-							Console.WriteLine("Assuming Open was successfully.");
-						break;
-					case "\\CLOSE":
-						Console.WriteLine("Attempt to Close...");
-						bool bCloseError = false;
-						try {
-							conn.Close();
-						}
-						catch(Exception e) {
-							Console.WriteLine("Exeception Caught Closing. " + e);
-							bCloseError = true;
-						}
-						if(bCloseError == false)
-							Console.WriteLine("Assuming Close was successfull.");
-						break;
-					case "\\EXECUTE":
-						if(conn == null)
-							Console.WriteLine("Error: connection is not Open.");
-						else if(conn.State == ConnectionState.Closed)
-							Console.WriteLine("Error: connection is not Open.");
+					case "F":		
+						if(a + 1 >= args.Length)
+							Console.WriteLine("Error: Missing FILENAME for -f switch");
 						else {
-							if(build == null)
-								Console.WriteLine("Error: SQL Buffer is empty.");
-							else {
-								string builtSQL = build.ToString();
-								Console.WriteLine("SQL: " + builtSQL);
-
-								RunStatement(builtSQL, provider);
-							}
-							build = null;
+							inputFilename = args[a + 1];
+							ExecuteBatch();
 						}
 						break;
-					case "\\H":
-						ShowHelp();
-						break;
-					case "\\Q":
+					case "O":
+						if(a + 1 >= args.Length)
+							Console.WriteLine("Error: Missing FILENAME for -o switch");
+						else
+							outputFilename = args[a + 1];
 						break;
 					default:
-						Console.WriteLine("Error: Unknown user command.");
+						Console.WriteLine("Error: Unknow switch: " + args[a]);
 						break;
 					}
+				}
+			}
+		}
+		
+		public void Run(string[] args) {
+
+			DealWithArgs(args);
+
+			string entry = "";
+			build = null;
+
+			if(silent == false) {
+				Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
+				Console.WriteLine("for Mono.Data.  See http://www.go-mono.com/ for more details.\n");
+						
+				ShowHelp();
+				ShowDefaults();
+			}
+			
+			while(entry.ToUpper().Equals("\\Q") == false &&
+				entry.ToUpper().Equals("\\QUIT") == false) {
 				
+				Console.Write("\nSQL# ");
+				entry = Console.ReadLine();
+
+				Console.WriteLine("Entered: " + entry);
+				
+				if(entry.Substring(0,1).Equals("\\")) {
+					HandleCommand(entry);
 				}
 				else if(entry.IndexOf(";") >= 0) {
 					// most likely the end of SQL Command or Query found
@@ -326,17 +554,11 @@ namespace Mono.Data.SqlSharp {
 					else if(conn.State == ConnectionState.Closed)
 						Console.WriteLine("Error: connection is not Open.");
 					else {
-						Console.WriteLine("if build == null");
 						if(build == null) {
-							Console.WriteLine("build is null, do new");
 							build = new StringBuilder();
 						}
-						Console.WriteLine("append entry");
 						build.Append(entry);
-						Console.WriteLine("build: " + build.ToString());
-						Console.WriteLine("RunStatement");
-						RunStatement(build.ToString(), provider);
-				
+						ExecuteSql(build.ToString());
 						build = null;
 					}
 				}
@@ -347,7 +569,6 @@ namespace Mono.Data.SqlSharp {
 						build = new StringBuilder();
 					}
 					build.Append(entry + " ");
-					Console.WriteLine("build: " + build.ToString());
 				}
 			}			
 		}