SqlSharpCli.cs 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373
  1. //
  2. // SqlSharpCli.cs - main driver for SqlSharp
  3. //
  4. // Currently, only working on a command line interface for SqlSharp
  5. //
  6. // However, once GTK# and System.Windows.Forms are good-to-go,
  7. // I would like to create a SqlSharpGui using this.
  8. //
  9. // It would be nice if this is included as part of Mono
  10. // extra goodies under Mono.Data.SqlSharp.
  11. //
  12. // Also, this makes a good Test program for Mono System.Data.
  13. // For more information about Mono::,
  14. // visit http://www.go-mono.com/
  15. //
  16. // To build SqlSharpCli.cs:
  17. // $ mcs SqlSharpCli.cs -r System.Data.dll
  18. //
  19. // To run with mono:
  20. // $ mono SqlSharpCli.exe
  21. //
  22. // To run with mint:
  23. // $ mint SqlSharpCli.exe
  24. //
  25. // To run batch commands and get the output, do something like:
  26. // $ cat commands.txt | mono SqlSharpCli.exe > results.txt
  27. //
  28. // Author:
  29. // Daniel Morgan <[email protected]>
  30. //
  31. // (C)Copyright 2002 Daniel Morgan
  32. //
  33. using System;
  34. using System.Collections;
  35. using System.Data;
  36. using System.Data.Common;
  37. using System.Data.Odbc;
  38. using System.Data.OleDb;
  39. using System.Data.SqlClient;
  40. using System.IO;
  41. using System.Reflection;
  42. using System.Runtime.Remoting;
  43. using System.Text;
  44. namespace Mono.Data.SqlSharp {
  45. public enum FileFormat {
  46. Html,
  47. Xml,
  48. CommaSeparatedValues,
  49. TabSeparated,
  50. Normal
  51. }
  52. // SQL Sharp - Command Line Interface
  53. public class SqlSharpCli {
  54. // provider supports
  55. private bool UseParameters = true;
  56. private bool UseSimpleReader = false;
  57. private IDbConnection conn = null;
  58. private string provider = "POSTGRESQL"; // name of internal provider
  59. // {OleDb,SqlClient,MySql,Odbc,Oracle,PostgreSql,SqlLite} however, it
  60. // can be set to LOADEXTPROVIDER to load an external provider
  61. private string providerAssembly = ""; // filename of assembly
  62. // for example: "Mono.Data.MySql"
  63. private string providerConnectionClass = ""; // Connection class
  64. // in the provider assembly that implements the IDbConnection
  65. // interface. for example: "Mono.Data.MySql.MySqlConnection"
  66. private StringBuilder build = null; // SQL string to build
  67. private string buff = ""; // SQL string buffer
  68. private string connectionString =
  69. "host=localhost;dbname=test;user=postgres";
  70. private string inputFilename = "";
  71. private string outputFilename = "";
  72. private StreamReader inputFilestream = null;
  73. private StreamWriter outputFilestream = null;
  74. private FileFormat outputFileFormat = FileFormat.Html;
  75. private bool silent = false;
  76. private bool showHeader = true;
  77. private Hashtable internalVariables = new Hashtable();
  78. // DisplayResult - used to Read() display a result set
  79. // called by DisplayData()
  80. public void DisplayResult(IDataReader reader, DataTable schemaTable) {
  81. StringBuilder line = null;
  82. StringBuilder hdrUnderline = null;
  83. int spacing = 0;
  84. int columnSize = 0;
  85. int c;
  86. char spacingChar = ' '; // a space
  87. char underlineChar = '='; // an equal sign
  88. string dataType; // .NET Type
  89. string dataTypeName; // native Database type
  90. DataRow row; // schema row
  91. line = new StringBuilder();
  92. hdrUnderline = new StringBuilder();
  93. OutputLine("Fields in Query Result: " +
  94. reader.FieldCount);
  95. OutputLine("");
  96. for(c = 0; c < schemaTable.Rows.Count; c++) {
  97. DataRow schemaRow = schemaTable.Rows[c];
  98. string columnHeader = (string) schemaRow["ColumnName"];
  99. int columnHeaderSize = columnHeader.Length;
  100. line.Append(columnHeader);
  101. hdrUnderline.Append(underlineChar, columnHeaderSize);
  102. // spacing
  103. columnSize = (int) schemaRow["ColumnSize"];
  104. dataType = (string) schemaRow["DataType"];
  105. dataTypeName = reader.GetDataTypeName(c);
  106. // columnSize correction based on data type
  107. if(dataType.Equals("System.Boolean")) {
  108. columnSize = 5;
  109. }
  110. if(provider.Equals("POSTGRESQL"))
  111. if(dataTypeName.Equals("text"))
  112. columnSize = 32; // text will be truncated to 32
  113. if(columnHeaderSize < columnSize) {
  114. spacing = columnSize - columnHeaderSize;
  115. line.Append(spacingChar, spacing);
  116. hdrUnderline.Append(underlineChar, spacing);
  117. }
  118. line.Append(" ");
  119. hdrUnderline.Append(" ");
  120. }
  121. OutputHeader(line.ToString());
  122. line = null;
  123. OutputHeader(hdrUnderline.ToString());
  124. OutputHeader("");
  125. hdrUnderline = null;
  126. // DEBUG - need to know the columnSize
  127. /*
  128. line = new StringBuilder();
  129. foreach(DataRow schemaRow in schemaTable.Rows) {
  130. columnSize = (int) schemaRow["ColumnSize"];
  131. line.Append(columnSize.ToString());
  132. line.Append(" ");
  133. }
  134. Console.WriteLine(line.ToString());
  135. Console.WriteLine();
  136. line = null;
  137. */
  138. int rows = 0;
  139. // column data
  140. while(reader.Read()) {
  141. rows++;
  142. line = new StringBuilder();
  143. for(c = 0; c < reader.FieldCount; c++) {
  144. int dataLen = 0;
  145. string dataValue;
  146. row = schemaTable.Rows[c];
  147. string colhdr = (string) row["ColumnName"];
  148. columnSize = (int) row["ColumnSize"];
  149. dataType = (string) row["DataType"];
  150. dataTypeName = reader.GetDataTypeName(c);
  151. // certain types need to have the
  152. // columnSize adjusted for display
  153. // so the column will line up for each
  154. // row and match the column header size
  155. if(dataType.Equals("System.Boolean")) {
  156. columnSize = 5;
  157. }
  158. if(provider.Equals("POSTGRESQL"))
  159. if(dataTypeName.Equals("text"))
  160. columnSize = 32; // text will be truncated to 32
  161. if(reader.IsDBNull(c)) {
  162. dataValue = "";
  163. dataLen = 0;
  164. }
  165. else {
  166. object obj = reader.GetValue(c);
  167. dataValue = obj.ToString();
  168. dataLen = dataValue.Length;
  169. line.Append(dataValue);
  170. }
  171. line.Append(" ");
  172. // spacing
  173. spacingChar = ' ';
  174. if(dataLen < columnSize) {
  175. spacing = columnSize - dataLen;
  176. line.Append(spacingChar, spacing);
  177. }
  178. spacingChar = ' ';
  179. if(columnSize < colhdr.Length) {
  180. spacing = colhdr.Length - columnSize;
  181. line.Append(spacingChar, spacing);
  182. }
  183. }
  184. OutputData(line.ToString());
  185. line = null;
  186. }
  187. OutputLine("\nRows retrieved: " + rows.ToString());
  188. }
  189. public void OutputDataToHtmlFile(IDataReader rdr, DataTable dt) {
  190. StringBuilder strHtml = new StringBuilder();
  191. strHtml.Append("<html> \n <head> <title>");
  192. strHtml.Append("Results");
  193. strHtml.Append("</title> </head>");
  194. strHtml.Append("<body>");
  195. strHtml.Append("<h1> Results </h1>");
  196. strHtml.Append("<table border=1>");
  197. outputFilestream.WriteLine(strHtml.ToString());
  198. strHtml = null;
  199. strHtml = new StringBuilder();
  200. strHtml.Append("<tr>");
  201. foreach (DataRow schemaRow in dt.Rows) {
  202. strHtml.Append("<td> <b>");
  203. object dataObj = schemaRow["ColumnName"];
  204. string sColumnName = dataObj.ToString();
  205. strHtml.Append(sColumnName);
  206. strHtml.Append("</b> </td>");
  207. }
  208. strHtml.Append("</tr>");
  209. outputFilestream.WriteLine(strHtml.ToString());
  210. strHtml = null;
  211. int col = 0;
  212. string dataValue = "";
  213. while(rdr.Read()) {
  214. strHtml = new StringBuilder();
  215. strHtml.Append("<tr>");
  216. for(col = 0; col < rdr.FieldCount; col++) {
  217. // column data
  218. if(rdr.IsDBNull(col) == true)
  219. dataValue = "NULL";
  220. else {
  221. object obj = rdr.GetValue(col);
  222. dataValue = obj.ToString();
  223. }
  224. strHtml.Append("<td>");
  225. strHtml.Append(dataValue);
  226. strHtml.Append("</td>");
  227. }
  228. strHtml.Append("\t\t</tr>");
  229. outputFilestream.WriteLine(strHtml.ToString());
  230. strHtml = null;
  231. }
  232. outputFilestream.WriteLine(" </table> </body> \n </html>");
  233. strHtml = null;
  234. }
  235. // DisplayData - used to display any Result Sets
  236. // from execution of SQL SELECT Query or Queries
  237. // called by DisplayData.
  238. // ExecuteSql() only calls this function
  239. // for a Query, it does not get
  240. // for a Command.
  241. public void DisplayData(IDataReader reader) {
  242. DataTable schemaTable = null;
  243. int ResultSet = 0;
  244. OutputLine("Display any result sets...");
  245. do {
  246. // by Default, SqlDataReader has the
  247. // first Result set if any
  248. ResultSet++;
  249. OutputLine("Display the result set " + ResultSet);
  250. schemaTable = reader.GetSchemaTable();
  251. if(reader.RecordsAffected >= 0) {
  252. // SQL Command (INSERT, UPDATE, or DELETE)
  253. // RecordsAffected >= 0
  254. Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
  255. }
  256. else if(schemaTable == null) {
  257. // SQL Command (not INSERT, UPDATE, nor DELETE)
  258. // RecordsAffected -1 and DataTable has a null reference
  259. Console.WriteLine("SQL Command Executed.");
  260. }
  261. else {
  262. // SQL Query (SELECT)
  263. // RecordsAffected -1 and DataTable has a reference
  264. OutputQueryResult(reader, schemaTable);
  265. }
  266. // get next result set (if anymore is left)
  267. } while(reader.NextResult());
  268. }
  269. // display the result in a simple way
  270. // new ADO.NET providers may have not certain
  271. // things implemented yet, such as, TableSchema
  272. // support
  273. public void DisplayDataSimple(IDataReader reader) {
  274. int row = 0;
  275. Console.WriteLine("Reading Data using simple reader...");
  276. while(reader.Read()){
  277. row++;
  278. Console.WriteLine("Row: " + row);
  279. for(int col = 0; col < reader.FieldCount; col++) {
  280. Console.WriteLine(" Field: " + col);
  281. //string dname = reader.GetName(col);
  282. //Console.WriteLine(" Name: " + dname);
  283. string dvalue = reader.GetValue(col).ToString();
  284. Console.WriteLine(" Value: " + dvalue);
  285. }
  286. }
  287. Console.WriteLine("\n" + row + " ROWS RETRIEVED\n");
  288. }
  289. public void OutputQueryResult(IDataReader dreader, DataTable dtable) {
  290. if(outputFilestream == null) {
  291. DisplayResult(dreader, dtable);
  292. }
  293. else {
  294. switch(outputFileFormat) {
  295. case FileFormat.Normal:
  296. DisplayResult(dreader, dtable);
  297. break;
  298. case FileFormat.Html:
  299. OutputDataToHtmlFile(dreader, dtable);
  300. break;
  301. default:
  302. Console.WriteLine("Error: Output data file format not supported.");
  303. break;
  304. }
  305. }
  306. }
  307. public void BuildParameters(IDbCommand cmd) {
  308. if(UseParameters == true) {
  309. ParametersBuilder parmsBuilder =
  310. new ParametersBuilder(cmd,
  311. BindVariableCharacter.Colon);
  312. Console.WriteLine("Get Parameters (if any)...");
  313. parmsBuilder.ParseParameters();
  314. IList parms = (IList) cmd.Parameters;
  315. Console.WriteLine("Print each parm...");
  316. for(int p = 0; p < parms.Count; p++) {
  317. string theParmName;
  318. IDataParameter prm = (IDataParameter) parms[p];
  319. theParmName = prm.ParameterName;
  320. string inValue = "";
  321. bool found;
  322. if(parmsBuilder.ParameterMarkerCharacter == '?') {
  323. Console.Write("Enter Parameter " +
  324. (p + 1).ToString() +
  325. ": ");
  326. inValue = Console.ReadLine();
  327. prm.Value = inValue;
  328. }
  329. else {
  330. found = GetInternalVariable(theParmName, out inValue);
  331. if(found == true) {
  332. prm.Value = inValue;
  333. }
  334. else {
  335. Console.Write("Enter Parameter " + (p + 1).ToString() +
  336. ": " + theParmName + ": ");
  337. inValue = Console.ReadLine();
  338. prm.Value = inValue;
  339. }
  340. }
  341. }
  342. parmsBuilder = null;
  343. }
  344. }
  345. // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
  346. public void ExecuteSql(string sql) {
  347. Console.WriteLine("Execute SQL: " + sql);
  348. IDbCommand cmd = null;
  349. IDataReader reader = null;
  350. cmd = conn.CreateCommand();
  351. // set command properties
  352. cmd.CommandType = CommandType.Text;
  353. cmd.CommandText = sql;
  354. cmd.Connection = conn;
  355. BuildParameters(cmd);
  356. try {
  357. reader = cmd.ExecuteReader();
  358. if(UseSimpleReader == false)
  359. DisplayData(reader);
  360. else
  361. DisplayDataSimple(reader);
  362. reader.Close();
  363. reader = null;
  364. }
  365. catch(Exception e) {
  366. Console.WriteLine("Exception Caught Executing SQL: " + e);
  367. //if(reader != null) {
  368. // if(reader.IsClosed == false)
  369. // reader.Close();
  370. reader = null;
  371. //}
  372. }
  373. finally {
  374. // cmd.Dispose();
  375. cmd = null;
  376. }
  377. }
  378. // ExecuteSql - Execute the SQL Commands (no SELECTs)
  379. public void ExecuteSqlNonQuery(string sql) {
  380. Console.WriteLine("Execute SQL Non Query: " + sql);
  381. IDbCommand cmd = null;
  382. int rowsAffected = -1;
  383. cmd = conn.CreateCommand();
  384. // set command properties
  385. cmd.CommandType = CommandType.Text;
  386. cmd.CommandText = sql;
  387. cmd.Connection = conn;
  388. BuildParameters(cmd);
  389. try {
  390. rowsAffected = cmd.ExecuteNonQuery();
  391. cmd = null;
  392. Console.WriteLine("Rows affected: " + rowsAffected);
  393. }
  394. catch(Exception e) {
  395. Console.WriteLine("Exception Caught Executing SQL: " + e);
  396. }
  397. finally {
  398. // cmd.Dispose();
  399. cmd = null;
  400. }
  401. }
  402. public void ExecuteSqlScalar(string sql) {
  403. Console.WriteLine("Execute SQL Scalar: " + sql);
  404. IDbCommand cmd = null;
  405. string retrievedValue = "";
  406. cmd = conn.CreateCommand();
  407. // set command properties
  408. cmd.CommandType = CommandType.Text;
  409. cmd.CommandText = sql;
  410. cmd.Connection = conn;
  411. BuildParameters(cmd);
  412. try {
  413. retrievedValue = (string) cmd.ExecuteScalar().ToString();
  414. Console.WriteLine("Retrieved value: " + retrievedValue);
  415. }
  416. catch(Exception e) {
  417. Console.WriteLine("Exception Caught Executing SQL: " + e);
  418. }
  419. finally {
  420. // cmd.Dispose();
  421. cmd = null;
  422. }
  423. }
  424. public void ExecuteSqlXml(string sql) {
  425. Console.WriteLine("Error: Not implemented yet.");
  426. }
  427. // like ShowHelp - but only show at the beginning
  428. // only the most important commands are shown
  429. // like help and quit
  430. public void StartupHelp() {
  431. Console.WriteLine(@"Type: \Q to quit");
  432. Console.WriteLine(@" \ConnectionString to set the ConnectionString");
  433. Console.WriteLine(@" \Provider to set the Provider:");
  434. Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
  435. Console.WriteLine(@" Oracle,PostgreSql,Sqlite)");
  436. Console.WriteLine(@" \Open to open the connection");
  437. Console.WriteLine(@" \Close to close the connection");
  438. Console.WriteLine(@" \Execute to execute SQL command(s)/queries(s)");
  439. Console.WriteLine(@" \h to show this help.");
  440. Console.WriteLine(@" \defaults to show default variables.");
  441. Console.WriteLine();
  442. }
  443. // ShowHelp - show the help - command a user can enter
  444. public void ShowHelp() {
  445. Console.WriteLine("");
  446. Console.WriteLine(@"Type: \Q to quit");
  447. Console.WriteLine(@" \ConnectionString to set the ConnectionString");
  448. Console.WriteLine(@" \Provider to set the Provider:");
  449. Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
  450. Console.WriteLine(@" Oracle,PostgreSql, Sqlite}");
  451. Console.WriteLine(@" \Open to open the connection");
  452. Console.WriteLine(@" \Close to close the connection");
  453. Console.WriteLine(@" \Execute to execute SQL command(s)/queries(s)");
  454. Console.WriteLine(@" \exenonquery execute an SQL non query (not a SELECT).");
  455. Console.WriteLine(@" \exescalar execute SQL to get a single row/single column result.");
  456. Console.WriteLine(@" \f FILENAME to read a batch of Sql# commands/queries from.");
  457. Console.WriteLine(@" \o FILENAME to write out the result of commands executed.");
  458. Console.WriteLine(@" \load FILENAME to load from file SQL commands into SQL buffer.");
  459. Console.WriteLine(@" \save FILENAME to save SQL commands from SQL buffer to file.");
  460. Console.WriteLine(@" \h to show this help.");
  461. Console.WriteLine(@" \defaults to show default variables, such as,");
  462. Console.WriteLine(@" Provider and ConnectionString.");
  463. Console.WriteLine(@" \s {TRUE, FALSE} to silent messages.");
  464. Console.WriteLine(@" \r reset (clear) the query buffer.");
  465. Console.WriteLine(@" \set NAME VALUE - set an internal variable.");
  466. WaitForEnterKey();
  467. Console.WriteLine(@" \unset NAME - remove an internal variable.");
  468. Console.WriteLine(@" \variable NAME - display the value of an internal variable.");
  469. Console.WriteLine(@" \loadprovider CLASS - load the provider");
  470. Console.WriteLine(@" use the complete name of its connection class.");
  471. Console.WriteLine(@" \loadextprovider ASSEMBLY CLASS - load the provider");
  472. Console.WriteLine(@" use the complete name of its assembly and");
  473. Console.WriteLine(@" its Connection class.");
  474. Console.WriteLine(@" \print - show what's in the SQL buffer now.");
  475. Console.WriteLine(@" \UseParameters (TRUE,FALSE) - use parameters when executing SQL.");
  476. Console.WriteLine(@" \UseSimpleReader (TRUE,FALSE) - use simple reader when displaying results.");
  477. Console.WriteLine();
  478. }
  479. public void WaitForEnterKey() {
  480. Console.Write("Waiting... Press Enter key to continue. ");
  481. string entry = Console.ReadLine();
  482. }
  483. // ShowDefaults - show defaults for connection variables
  484. public void ShowDefaults() {
  485. Console.WriteLine();
  486. Console.WriteLine("The default Provider is " + provider);
  487. if(provider.Equals("LOADEXTPROVIDER")) {
  488. Console.WriteLine(" Assembly: " +
  489. providerAssembly);
  490. Console.WriteLine(" Connection Class: " +
  491. providerConnectionClass);
  492. }
  493. Console.WriteLine();
  494. Console.WriteLine("The default ConnectionString is: ");
  495. Console.WriteLine(" \"" + connectionString + "\"");
  496. Console.WriteLine();
  497. }
  498. // OpenDataSource - open connection to the data source
  499. public void OpenDataSource() {
  500. Console.WriteLine("Attempt to Open...");
  501. try {
  502. switch(provider) {
  503. case "ODBC":
  504. conn = new OdbcConnection();
  505. break;
  506. case "OLEDB":
  507. conn = new OleDbConnection();
  508. break;
  509. case "POSTGRESQL":
  510. // FIXME: System.Data.SqlClient should
  511. // be used for MS SQL Server 7/2000
  512. // and move the PostgreSQL provider
  513. // to Mono.Data.PostgreSQL
  514. // and use a connection class
  515. // PgSqlConnection
  516. conn = new SqlConnection();
  517. break;
  518. case "LOADEXTPROVIDER":
  519. if(LoadExternalProvider() == false)
  520. return;
  521. break;
  522. default:
  523. Console.WriteLine("Error: Bad argument or provider not supported.");
  524. return;
  525. }
  526. }
  527. catch(Exception e) {
  528. Console.WriteLine("Error: Unable to create Connection object. " + e);
  529. return;
  530. }
  531. conn.ConnectionString = connectionString;
  532. try {
  533. conn.Open();
  534. if(conn.State == ConnectionState.Open)
  535. Console.WriteLine("Open was successfull.");
  536. }
  537. catch(Exception e) {
  538. Console.WriteLine("Exception Caught Opening. " + e);
  539. conn = null;
  540. }
  541. }
  542. // CloseDataSource - close the connection to the data source
  543. public void CloseDataSource() {
  544. if(conn != null) {
  545. Console.WriteLine("Attempt to Close...");
  546. try {
  547. conn.Close();
  548. Console.WriteLine("Close was successfull.");
  549. }
  550. catch(Exception e) {
  551. Console.WriteLine("Exeception Caught Closing. " + e);
  552. }
  553. conn = null;
  554. }
  555. }
  556. // ChangeProvider - change the provider string variable
  557. public void ChangeProvider(string[] parms) {
  558. string[] extp;
  559. if(parms.Length == 2) {
  560. string parm = parms[1].ToUpper();
  561. switch(parm) {
  562. case "ORACLE":
  563. case "TDS":
  564. case "SYBASE":
  565. Console.WriteLine("Error: Provider not currently supported.");
  566. break;
  567. case "MYSQL":
  568. extp = new string[3] {
  569. "\\loadextprovider",
  570. "Mono.Data.MySql",
  571. "Mono.Data.MySql.MySqlConnection"};
  572. SetupExternalProvider(extp);
  573. UseParameters = false;
  574. UseSimpleReader = true;
  575. break;
  576. case "SQLITE":
  577. extp = new string[3] {
  578. "\\loadextprovider",
  579. "Mono.Data.SqliteClient",
  580. "Mono.Data.SqliteClient.SqliteConnection"};
  581. SetupExternalProvider(extp);
  582. UseParameters = false;
  583. UseSimpleReader = true;
  584. break;
  585. case "SQLCLIENT":
  586. provider = "POSTGRESQL";
  587. Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
  588. break;
  589. case "ODBC":
  590. case "GDA":
  591. case "OLEDB":
  592. UseParameters = false;
  593. UseSimpleReader = true;
  594. provider = parm;
  595. break;
  596. case "POSTGRESQL":
  597. UseParameters = true;
  598. UseSimpleReader = false;
  599. provider = parm;
  600. break;
  601. default:
  602. Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
  603. break;
  604. }
  605. Console.WriteLine("The default Provider is " + provider);
  606. if(provider.Equals("LOADEXTPROVIDER")) {
  607. Console.WriteLine(" Assembly: " +
  608. providerAssembly);
  609. Console.WriteLine(" Connection Class: " +
  610. providerConnectionClass);
  611. }
  612. }
  613. else
  614. Console.WriteLine("Error: provider only has one parameter.");
  615. }
  616. // ChangeConnectionString - change the connection string variable
  617. public void ChangeConnectionString(string entry) {
  618. if(entry.Length > 18)
  619. connectionString = entry.Substring(18, entry.Length - 18);
  620. else
  621. connectionString = "";
  622. }
  623. public void SetupOutputResultsFile(string[] parms) {
  624. if(parms.Length != 2) {
  625. Console.WriteLine("Error: wrong number of parameters");
  626. return;
  627. }
  628. try {
  629. outputFilestream = new StreamWriter(parms[1]);
  630. }
  631. catch(Exception e) {
  632. Console.WriteLine("Error: Unable to setup output results file. " + e);
  633. return;
  634. }
  635. }
  636. public void SetupInputCommandsFile(string[] parms) {
  637. if(parms.Length != 2) {
  638. Console.WriteLine("Error: wrong number of parameters");
  639. return;
  640. }
  641. try {
  642. inputFilestream = new StreamReader(parms[1]);
  643. }
  644. catch(Exception e) {
  645. Console.WriteLine("Error: Unable to setup input commmands file. " + e);
  646. return;
  647. }
  648. }
  649. public void LoadBufferFromFile(string[] parms) {
  650. if(parms.Length != 2) {
  651. Console.WriteLine("Error: wrong number of parameters");
  652. return;
  653. }
  654. string inFilename = parms[1];
  655. try {
  656. StreamReader sr = new StreamReader( inFilename);
  657. StringBuilder buffer = new StringBuilder();
  658. string NextLine;
  659. while((NextLine = sr.ReadLine()) != null) {
  660. buffer.Append(NextLine);
  661. buffer.Append("\n");
  662. }
  663. sr.Close();
  664. buff = buffer.ToString();
  665. build = null;
  666. build = new StringBuilder();
  667. build.Append(buff);
  668. }
  669. catch(Exception e) {
  670. Console.WriteLine("Error: Unable to read file into SQL Buffer. " + e);
  671. }
  672. }
  673. public void SaveBufferToFile(string[] parms) {
  674. if(parms.Length != 2) {
  675. Console.WriteLine("Error: wrong number of parameters");
  676. return;
  677. }
  678. string outFilename = parms[1];
  679. try {
  680. StreamWriter sw = new StreamWriter(outFilename);
  681. sw.WriteLine(buff);
  682. sw.Close();
  683. }
  684. catch(Exception e) {
  685. Console.WriteLine("Error: Could not save SQL Buffer to file." + e);
  686. }
  687. }
  688. public void SetUseParameters(string[] parms) {
  689. if(parms.Length != 2) {
  690. Console.WriteLine("Error: wrong number of parameters");
  691. return;
  692. }
  693. string parm = parms[1].ToUpper();
  694. if(parm.Equals("TRUE"))
  695. UseParameters = true;
  696. else if(parm.Equals("FALSE"))
  697. UseParameters = false;
  698. else
  699. Console.WriteLine("Error: invalid parameter.");
  700. }
  701. public void SetUseSimpleReader(string[] parms) {
  702. if(parms.Length != 2) {
  703. Console.WriteLine("Error: wrong number of parameters");
  704. return;
  705. }
  706. string parm = parms[1].ToUpper();
  707. if(parm.Equals("TRUE"))
  708. UseSimpleReader = true;
  709. else if(parm.Equals("FALSE"))
  710. UseSimpleReader = false;
  711. else
  712. Console.WriteLine("Error: invalid parameter.");
  713. }
  714. public void SetupSilentMode(string[] parms) {
  715. if(parms.Length != 2) {
  716. Console.WriteLine("Error: wrong number of parameters");
  717. return;
  718. }
  719. string parm = parms[1].ToUpper();
  720. if(parm.Equals("TRUE"))
  721. silent = true;
  722. else if(parm.Equals("FALSE"))
  723. silent = false;
  724. else
  725. Console.WriteLine("Error: invalid parameter.");
  726. }
  727. public void SetInternalVariable(string[] parms) {
  728. if(parms.Length < 2) {
  729. Console.WriteLine("Error: wrong number of parameters.");
  730. return;
  731. }
  732. string parm = parms[1];
  733. StringBuilder ps = new StringBuilder();
  734. for(int i = 2; i < parms.Length; i++)
  735. ps.Append(parms[i]);
  736. internalVariables[parm] = ps.ToString();
  737. }
  738. public void UnSetInternalVariable(string[] parms) {
  739. if(parms.Length != 2) {
  740. Console.WriteLine("Error: wrong number of parameters.");
  741. return;
  742. }
  743. string parm = parms[1];
  744. try {
  745. internalVariables.Remove(parm);
  746. }
  747. catch(Exception e) {
  748. Console.WriteLine("Error: internal variable does not exist.");
  749. }
  750. }
  751. public void ShowInternalVariable(string[] parms) {
  752. string internalVariableValue = "";
  753. if(parms.Length != 2) {
  754. Console.WriteLine("Error: wrong number of parameters.");
  755. return;
  756. }
  757. string parm = parms[1];
  758. if(GetInternalVariable(parm, out internalVariableValue) == true)
  759. Console.WriteLine("Internal Variable - Name: " +
  760. parm + " Value: " + internalVariableValue);
  761. }
  762. public bool GetInternalVariable(string name, out string sValue) {
  763. sValue = "";
  764. bool valueReturned = false;
  765. try {
  766. if(internalVariables.ContainsKey(name) == true) {
  767. sValue = (string) internalVariables[name];
  768. valueReturned = true;
  769. }
  770. else
  771. Console.WriteLine("Error: internal variable does not exist.");
  772. }
  773. catch(Exception e) {
  774. Console.WriteLine("Error: internal variable does not exist.");
  775. }
  776. return valueReturned;
  777. }
  778. // to be used for loading .NET Data Providers that exist in
  779. // the System.Data assembly, but are not explicitly handling
  780. // in SQL#
  781. public void LoadProvider(string[] parms) {
  782. Console.WriteLine("Error: not implemented yet.");
  783. }
  784. public void SetupExternalProvider(string[] parms) {
  785. if(parms.Length != 3) {
  786. Console.WriteLine("Error: Wrong number of parameters.");
  787. return;
  788. }
  789. provider = "LOADEXTPROVIDER";
  790. providerAssembly = parms[1];
  791. providerConnectionClass = parms[2];
  792. }
  793. public bool LoadExternalProvider() {
  794. bool success = false;
  795. // For example: for the MySQL provider in Mono.Data.MySql
  796. // \LoadExtProvider Mono.Data.MySql Mono.Data.MySql.MySqlConnection
  797. // \ConnectionString dbname=test
  798. // \open
  799. // insert into sometable (tid, tdesc, aint) values ('abc','def',12)
  800. // \exenonquery
  801. // \close
  802. // \quit
  803. try {
  804. Console.WriteLine("Loading external provider...");
  805. Console.Out.Flush();
  806. Assembly ps = Assembly.Load(providerAssembly);
  807. Type typ = ps.GetType(providerConnectionClass);
  808. conn = (IDbConnection) Activator.CreateInstance(typ);
  809. success = true;
  810. Console.WriteLine("External provider loaded.");
  811. Console.Out.Flush();
  812. }
  813. catch(FileNotFoundException f) {
  814. Console.WriteLine("Error: unable to load the assembly of the provider: " +
  815. providerAssembly);
  816. }
  817. return success;
  818. }
  819. // used for outputting message, but if silent is set,
  820. // don't display
  821. public void OutputLine(string line) {
  822. if(silent == false)
  823. OutputData(line);
  824. }
  825. // used for outputting the header columns of a result
  826. public void OutputHeader(string line) {
  827. if(showHeader == true)
  828. OutputData(line);
  829. }
  830. // OutputData() - used for outputting data
  831. // if an output filename is set, then the data will
  832. // go to a file; otherwise, it will go to the Console.
  833. public void OutputData(string line) {
  834. if(outputFilestream == null)
  835. Console.WriteLine(line);
  836. else
  837. outputFilestream.WriteLine(line);
  838. }
  839. // HandleCommand - handle SqlSharpCli commands entered
  840. public void HandleCommand(string entry) {
  841. string[] parms;
  842. parms = entry.Split(new char[1] {' '});
  843. string userCmd = parms[0].ToUpper();
  844. switch(userCmd) {
  845. case "\\PROVIDER":
  846. ChangeProvider(parms);
  847. break;
  848. case "\\CONNECTIONSTRING":
  849. ChangeConnectionString(entry);
  850. break;
  851. case "\\LOADPROVIDER":
  852. // TODO:
  853. //SetupProvider(parms);
  854. break;
  855. case "\\LOADEXTPROVIDER":
  856. SetupExternalProvider(parms);
  857. break;
  858. case "\\OPEN":
  859. OpenDataSource();
  860. break;
  861. case "\\CLOSE":
  862. CloseDataSource();
  863. break;
  864. case "\\S":
  865. SetupSilentMode(parms);
  866. break;
  867. case "\\E":
  868. case "\\EXECUTE":
  869. // Execute SQL Commands or Queries
  870. if(conn == null)
  871. Console.WriteLine("Error: connection is not Open.");
  872. else if(conn.State == ConnectionState.Closed)
  873. Console.WriteLine("Error: connection is not Open.");
  874. else {
  875. if(build == null)
  876. Console.WriteLine("Error: SQL Buffer is empty.");
  877. else {
  878. buff = build.ToString();
  879. ExecuteSql(buff);
  880. }
  881. build = null;
  882. }
  883. break;
  884. case "\\EXENONQUERY":
  885. if(conn == null)
  886. Console.WriteLine("Error: connection is not Open.");
  887. else if(conn.State == ConnectionState.Closed)
  888. Console.WriteLine("Error: connection is not Open.");
  889. else {
  890. if(build == null)
  891. Console.WriteLine("Error: SQL Buffer is empty.");
  892. else {
  893. buff = build.ToString();
  894. ExecuteSqlNonQuery(buff);
  895. }
  896. build = null;
  897. }
  898. break;
  899. case "\\EXESCALAR":
  900. if(conn == null)
  901. Console.WriteLine("Error: connection is not Open.");
  902. else if(conn.State == ConnectionState.Closed)
  903. Console.WriteLine("Error: connection is not Open.");
  904. else {
  905. if(build == null)
  906. Console.WriteLine("Error: SQL Buffer is empty.");
  907. else {
  908. buff = build.ToString();
  909. ExecuteSqlScalar(buff);
  910. }
  911. build = null;
  912. }
  913. break;
  914. case "\\F":
  915. SetupInputCommandsFile(parms);
  916. break;
  917. case "\\O":
  918. SetupOutputResultsFile(parms);
  919. break;
  920. case "\\LOAD":
  921. // Load file into SQL buffer: \load FILENAME
  922. LoadBufferFromFile(parms);
  923. break;
  924. case "\\SAVE":
  925. // Save SQL buffer to file: \save FILENAME
  926. SaveBufferToFile(parms);
  927. break;
  928. case "\\H":
  929. case "\\HELP":
  930. // Help
  931. ShowHelp();
  932. break;
  933. case "\\DEFAULTS":
  934. // show the defaults for provider and connection strings
  935. ShowDefaults();
  936. break;
  937. case "\\Q":
  938. case "\\QUIT":
  939. // Quit
  940. break;
  941. case "\\R":
  942. // reset (clear) the query buffer
  943. build = null;
  944. break;
  945. case "\\SET":
  946. // sets internal variable
  947. // \set name value
  948. SetInternalVariable(parms);
  949. break;
  950. case "\\UNSET":
  951. // deletes internal variable
  952. // \unset name
  953. UnSetInternalVariable(parms);
  954. break;
  955. case "\\VARIABLE":
  956. ShowInternalVariable(parms);
  957. break;
  958. case "\\PRINT":
  959. if(build == null)
  960. Console.WriteLine("SQL Buffer is empty.");
  961. else
  962. Console.WriteLine("SQL Bufer:\n" + buff);
  963. break;
  964. case "\\USEPARAMETERS":
  965. SetUseParameters(parms);
  966. break;
  967. case "\\USESIMPLEREADER":
  968. SetUseSimpleReader(parms);
  969. break;
  970. default:
  971. // Error
  972. Console.WriteLine("Error: Unknown user command.");
  973. break;
  974. }
  975. }
  976. public void DealWithArgs(string[] args) {
  977. for(int a = 0; a < args.Length; a++) {
  978. if(args[a].Substring(0,1).Equals("-")) {
  979. string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
  980. switch(arg) {
  981. case "S":
  982. silent = true;
  983. break;
  984. case "F":
  985. if(a + 1 >= args.Length)
  986. Console.WriteLine("Error: Missing FILENAME for -f switch");
  987. else {
  988. inputFilename = args[a + 1];
  989. inputFilestream = new StreamReader(inputFilename);
  990. }
  991. break;
  992. case "O":
  993. if(a + 1 >= args.Length)
  994. Console.WriteLine("Error: Missing FILENAME for -o switch");
  995. else {
  996. outputFilename = args[a + 1];
  997. outputFilestream = new StreamWriter(outputFilename);
  998. }
  999. break;
  1000. default:
  1001. Console.WriteLine("Error: Unknow switch: " + args[a]);
  1002. break;
  1003. }
  1004. }
  1005. }
  1006. }
  1007. public string ReadSqlSharpCommand() {
  1008. string entry = "";
  1009. if(inputFilestream == null) {
  1010. Console.Write("\nSQL# ");
  1011. entry = Console.ReadLine();
  1012. }
  1013. else {
  1014. try {
  1015. entry = inputFilestream.ReadLine();
  1016. if(entry == null) {
  1017. Console.WriteLine("Executing SQL# Commands from file done.");
  1018. }
  1019. }
  1020. catch(Exception e) {
  1021. Console.WriteLine("Error: Reading command from file.");
  1022. }
  1023. Console.Write("\nSQL# ");
  1024. entry = Console.ReadLine();
  1025. }
  1026. return entry;
  1027. }
  1028. public void Run(string[] args) {
  1029. DealWithArgs(args);
  1030. string entry = "";
  1031. build = null;
  1032. if(silent == false) {
  1033. Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
  1034. Console.WriteLine("for Mono.Data. See http://www.go-mono.com/ for more details.\n");
  1035. StartupHelp();
  1036. ShowDefaults();
  1037. }
  1038. while(entry.ToUpper().Equals("\\Q") == false &&
  1039. entry.ToUpper().Equals("\\QUIT") == false) {
  1040. entry = ReadSqlSharpCommand();
  1041. if(entry.Substring(0,1).Equals("\\")) {
  1042. HandleCommand(entry);
  1043. }
  1044. else if(entry.IndexOf(";") >= 0) {
  1045. // most likely the end of SQL Command or Query found
  1046. // execute the SQL
  1047. if(conn == null)
  1048. Console.WriteLine("Error: connection is not Open.");
  1049. else if(conn.State == ConnectionState.Closed)
  1050. Console.WriteLine("Error: connection is not Open.");
  1051. else {
  1052. if(build == null) {
  1053. build = new StringBuilder();
  1054. }
  1055. build.Append(entry);
  1056. //build.Append("\n");
  1057. buff = build.ToString();
  1058. ExecuteSql(buff);
  1059. build = null;
  1060. }
  1061. }
  1062. else {
  1063. // most likely a part of a SQL Command or Query found
  1064. // append this part of the SQL
  1065. if(build == null) {
  1066. build = new StringBuilder();
  1067. }
  1068. build.Append(entry + "\n");
  1069. buff = build.ToString();
  1070. }
  1071. }
  1072. CloseDataSource();
  1073. if(outputFilestream != null)
  1074. outputFilestream.Close();
  1075. }
  1076. }
  1077. public enum BindVariableCharacter {
  1078. Colon, // ':' - named parameter - :name
  1079. At, // '@' - named parameter - @name
  1080. QuestionMark, // '?' - positioned parameter - ?
  1081. SquareBrackets // '[]' - delimited named parameter - [name]
  1082. }
  1083. public class ParametersBuilder {
  1084. private BindVariableCharacter bindCharSetting;
  1085. private char bindChar;
  1086. private IDataParameterCollection parms;
  1087. private string sql;
  1088. private IDbCommand cmd;
  1089. private void SetBindCharacter() {
  1090. switch(bindCharSetting) {
  1091. case BindVariableCharacter.Colon:
  1092. bindChar = ':';
  1093. break;
  1094. case BindVariableCharacter.At:
  1095. bindChar = '@';
  1096. break;
  1097. case BindVariableCharacter.SquareBrackets:
  1098. bindChar = '[';
  1099. break;
  1100. case BindVariableCharacter.QuestionMark:
  1101. bindChar = '?';
  1102. break;
  1103. }
  1104. }
  1105. public ParametersBuilder(IDbCommand command, BindVariableCharacter bindVarChar) {
  1106. cmd = command;
  1107. sql = cmd.CommandText;
  1108. parms = cmd.Parameters;
  1109. bindCharSetting = bindVarChar;
  1110. SetBindCharacter();
  1111. }
  1112. public char ParameterMarkerCharacter {
  1113. get {
  1114. return bindChar;
  1115. }
  1116. }
  1117. public int ParseParameters() {
  1118. int numParms = 0;
  1119. IDataParameterCollection parms = cmd.Parameters;
  1120. char[] chars = sql.ToCharArray();
  1121. bool bStringConstFound = false;
  1122. for(int i = 0; i < chars.Length; i++) {
  1123. if(chars[i] == '\'') {
  1124. if(bStringConstFound == true)
  1125. bStringConstFound = false;
  1126. else
  1127. bStringConstFound = true;
  1128. }
  1129. else if(chars[i] == bindChar &&
  1130. bStringConstFound == false) {
  1131. if(bindChar != '?') {
  1132. StringBuilder parm = new StringBuilder();
  1133. i++;
  1134. if(bindChar.Equals('[')) {
  1135. bool endingBracketFound = false;
  1136. while(i <= chars.Length) {
  1137. char ch;
  1138. if(i == chars.Length)
  1139. ch = ' '; // a space
  1140. else
  1141. ch = chars[i];
  1142. if(Char.IsLetterOrDigit(ch) || ch == ' ') {
  1143. parm.Append(ch);
  1144. }
  1145. else if (ch == ']') {
  1146. endingBracketFound = true;
  1147. string p = parm.ToString();
  1148. AddParameter(p);
  1149. numParms ++;
  1150. break;
  1151. }
  1152. else throw new Exception("SQL Parser Error: Invalid character in parameter name");
  1153. i++;
  1154. }
  1155. i--;
  1156. if(endingBracketFound == false)
  1157. throw new Exception("SQL Parser Error: Ending bracket not found for parameter");
  1158. }
  1159. else {
  1160. while(i <= chars.Length) {
  1161. char ch;
  1162. if(i == chars.Length)
  1163. ch = ' '; // a space
  1164. else
  1165. ch = chars[i];
  1166. if(Char.IsLetterOrDigit(ch)) {
  1167. parm.Append(ch);
  1168. }
  1169. else {
  1170. string p = parm.ToString();
  1171. AddParameter(p);
  1172. numParms ++;
  1173. break;
  1174. }
  1175. i++;
  1176. }
  1177. i--;
  1178. }
  1179. }
  1180. else {
  1181. // placeholder paramaeter for ?
  1182. string p = numParms.ToString();
  1183. AddParameter(p);
  1184. numParms ++;
  1185. }
  1186. }
  1187. }
  1188. return numParms;
  1189. }
  1190. public void AddParameter (string p) {
  1191. Console.WriteLine("Add Parameter: " + p);
  1192. if(parms.Contains(p) == false) {
  1193. IDataParameter prm = cmd.CreateParameter();
  1194. prm.ParameterName = p;
  1195. prm.Direction = ParameterDirection.Input;
  1196. prm.DbType = DbType.String; // default
  1197. prm.Value = ""; // default
  1198. cmd.Parameters.Add(prm);
  1199. }
  1200. }
  1201. }
  1202. public class SqlSharpDriver {
  1203. public static void Main(string[] args) {
  1204. SqlSharpCli sqlCommandLineEngine = new SqlSharpCli();
  1205. sqlCommandLineEngine.Run(args);
  1206. }
  1207. }
  1208. }