SqlSharpCli.cs 32 KB

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