SqlSharpCli.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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 -r Mono.Data.MySql.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 Mono.Data.MySql;
  34. using System;
  35. using System.Data;
  36. using System.Data.Common;
  37. using System.Data.SqlClient;
  38. using System.IO;
  39. using System.Text;
  40. namespace Mono.Data.SqlSharp {
  41. // SQL Sharp - Command Line Interface
  42. public class SqlSharpCli {
  43. private IDbConnection conn = null;
  44. private string provider = "POSTGRESCLIENT";
  45. private StringBuilder build = null; // SQL string to build
  46. private string connectionString =
  47. "host=localhost;dbname=test;user=postgres";
  48. private string inputFilename = "";
  49. private string outputFilename = "";
  50. private bool silent = false;
  51. // DisplayResult - used to Read() display a result set
  52. // called by DisplayData()
  53. public void DisplayResult(IDataReader reader, DataTable schemaTable) {
  54. StringBuilder line = null;
  55. StringBuilder hdrUnderline = null;
  56. int spacing = 0;
  57. int columnSize = 0;
  58. int c;
  59. char spacingChar = ' '; // a space
  60. char underlineChar = '='; // an equal sign
  61. string dataType; // .NET Type
  62. string dataTypeName; // native Database type
  63. DataRow row; // schema row
  64. line = new StringBuilder();
  65. hdrUnderline = new StringBuilder();
  66. Console.WriteLine("Fields in Query Result: " +
  67. reader.FieldCount);
  68. Console.WriteLine();
  69. for(c = 0; c < schemaTable.Rows.Count; c++) {
  70. DataRow schemaRow = schemaTable.Rows[c];
  71. string columnHeader = (string) schemaRow["ColumnName"];
  72. int columnHeaderSize = columnHeader.Length;
  73. line.Append(columnHeader);
  74. hdrUnderline.Append(underlineChar, columnHeaderSize);
  75. // spacing
  76. columnSize = (int) schemaRow["ColumnSize"];
  77. dataType = (string) schemaRow["DataType"];
  78. dataTypeName = reader.GetDataTypeName(c);
  79. // columnSize correction based on data type
  80. if(dataType.Equals("System.Boolean")) {
  81. columnSize = 5;
  82. }
  83. if(provider.Equals("POSTGRESCLIENT"))
  84. if(dataTypeName.Equals("text"))
  85. columnSize = 32; // text will be truncated to 32
  86. if(columnHeaderSize < columnSize) {
  87. spacing = columnSize - columnHeaderSize;
  88. line.Append(spacingChar, spacing);
  89. hdrUnderline.Append(underlineChar, spacing);
  90. }
  91. line.Append(" ");
  92. hdrUnderline.Append(" ");
  93. }
  94. Console.WriteLine(line.ToString());
  95. line = null;
  96. Console.WriteLine(hdrUnderline);
  97. Console.WriteLine();
  98. hdrUnderline = null;
  99. // DEBUG - need to know the columnSize
  100. /*
  101. line = new StringBuilder();
  102. foreach(DataRow schemaRow in schemaTable.Rows) {
  103. columnSize = (int) schemaRow["ColumnSize"];
  104. line.Append(columnSize.ToString());
  105. line.Append(" ");
  106. }
  107. Console.WriteLine(line.ToString());
  108. Console.WriteLine();
  109. line = null;
  110. */
  111. int rows = 0;
  112. // column data
  113. while(reader.Read()) {
  114. rows++;
  115. line = new StringBuilder();
  116. for(c = 0; c < reader.FieldCount; c++) {
  117. int dataLen = 0;
  118. string dataValue;
  119. row = schemaTable.Rows[c];
  120. string colhdr = (string) row["ColumnName"];
  121. columnSize = (int) row["ColumnSize"];
  122. dataType = (string) row["DataType"];
  123. dataTypeName = reader.GetDataTypeName(c);
  124. // certain types need to have the
  125. // columnSize adjusted for display
  126. // so the column will line up for each
  127. // row and match the column header size
  128. if(dataType.Equals("System.Boolean")) {
  129. columnSize = 5;
  130. }
  131. if(provider.Equals("POSTGRESCLIENT"))
  132. if(dataTypeName.Equals("text"))
  133. columnSize = 32; // text will be truncated to 32
  134. if(reader.IsDBNull(c)) {
  135. dataValue = "";
  136. dataLen = 0;
  137. }
  138. else {
  139. object obj = reader.GetValue(c);
  140. dataValue = obj.ToString();
  141. dataLen = dataValue.Length;
  142. line.Append(dataValue);
  143. }
  144. line.Append(" ");
  145. // spacing
  146. spacingChar = ' ';
  147. if(dataLen < columnSize) {
  148. spacing = columnSize - dataLen;
  149. line.Append(spacingChar, spacing);
  150. }
  151. spacingChar = ' ';
  152. if(columnSize < colhdr.Length) {
  153. spacing = colhdr.Length - columnSize;
  154. line.Append(spacingChar, spacing);
  155. }
  156. }
  157. Console.WriteLine(line.ToString());
  158. line = null;
  159. }
  160. Console.WriteLine("\nRows retrieved: " + rows);
  161. }
  162. // DisplayData - used to display any Result Sets
  163. // from execution of SQL SELECT Query or Queries
  164. // called by DisplayData.
  165. // ExecuteSql() only calls this function
  166. // for a Query, it does not get
  167. // for a Command.
  168. public void DisplayData(IDataReader reader) {
  169. DataTable schemaTable = null;
  170. int ResultSet = 0;
  171. Console.WriteLine("Display any result sets...");
  172. do {
  173. // by Default, SqlDataReader has the
  174. // first Result set if any
  175. ResultSet++;
  176. Console.WriteLine("Display the result set " + ResultSet);
  177. schemaTable = reader.GetSchemaTable();
  178. if(reader.RecordsAffected >= 0) {
  179. // SQL Command (INSERT, UPDATE, or DELETE)
  180. // RecordsAffected >= 0
  181. Console.WriteLine("SQL Command Records Affected: " + reader.RecordsAffected);
  182. }
  183. else if(schemaTable == null) {
  184. // SQL Command (not INSERT, UPDATE, nor DELETE)
  185. // RecordsAffected -1 and DataTable has a null reference
  186. Console.WriteLine("SQL Command Executed.");
  187. }
  188. else {
  189. // SQL Query (SELECT)
  190. // RecordsAffected -1 and DataTable has a reference
  191. DisplayResult(reader, schemaTable);
  192. }
  193. // get next result set (if anymore is left)
  194. } while(reader.NextResult());
  195. }
  196. // ExecuteSql - Execute the SQL Command(s) and/or Query(ies)
  197. public void ExecuteSql(string sql) {
  198. Console.WriteLine("Execute SQL: " + sql);
  199. IDbCommand cmd = null;
  200. IDataReader reader = null;
  201. // create a Command object based on the provider
  202. switch(provider) {
  203. //case "OLEDB":
  204. // cmd = new OleDbCommand();
  205. // break;
  206. case "MYSQL":
  207. cmd = new MySqlCommand();
  208. break;
  209. case "POSTGRESCLIENT":
  210. cmd = new SqlCommand();
  211. break;
  212. default:
  213. Console.WriteLine("Error: PostgreSQL is only supported, and it through SqlClient.");
  214. return;
  215. }
  216. // set command properties
  217. cmd.CommandType = CommandType.Text;
  218. cmd.CommandText = sql;
  219. cmd.Connection = conn;
  220. try {
  221. reader = cmd.ExecuteReader();
  222. DisplayData(reader);
  223. reader.Close();
  224. //reader = null;
  225. //cmd.Dispose();
  226. //cmd = null;
  227. }
  228. catch(Exception e) {
  229. Console.WriteLine("Exception Caught Executing SQL: " + e);
  230. //if(reader != null) {
  231. // if(reader.IsClosed == false)
  232. // reader.Close();
  233. // reader = null;
  234. //}
  235. // cmd.Dispose();
  236. //cmd = null;
  237. }
  238. }
  239. // like ShowHelp - but only show at the beginning
  240. // only the most important commands are shown
  241. // like help and quit
  242. public void StartupHelp() {
  243. Console.WriteLine(@"Type: \Q to quit");
  244. Console.WriteLine(@" \ConnectionString to set the ConnectionString");
  245. Console.WriteLine(@" \Provider to set the Provider:");
  246. Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
  247. Console.WriteLine(@" OracleClient,PostgresClient}");
  248. Console.WriteLine(@" \Open to open the connection");
  249. Console.WriteLine(@" \Close to close the connection");
  250. Console.WriteLine(@" \Execute to execute SQL command(s)/queries(s)");
  251. Console.WriteLine(@" \h to show this help.");
  252. Console.WriteLine(@" \defaults to show default variables.");
  253. Console.WriteLine();
  254. }
  255. // ShowHelp - show the help - command a user can enter
  256. public void ShowHelp() {
  257. Console.WriteLine("");
  258. Console.WriteLine(@"Type: \Q to quit");
  259. Console.WriteLine(@" \ConnectionString to set the ConnectionString");
  260. Console.WriteLine(@" \Provider to set the Provider:");
  261. Console.WriteLine(@" {OleDb,SqlClient,MySql,Odbc,");
  262. Console.WriteLine(@" OracleClient,PostgresClient}");
  263. Console.WriteLine(@" \Open to open the connection");
  264. Console.WriteLine(@" \Close to close the connection");
  265. Console.WriteLine(@" \Execute to execute SQL command(s)/queries(s)");
  266. Console.WriteLine(@" \f FILENAME to read a batch of commands from");
  267. Console.WriteLine(@" \o FILENAME to read a batch of commands from");
  268. Console.WriteLine(@" \h to show this help.");
  269. Console.WriteLine(@" \defaults to show default variables.");
  270. Console.WriteLine(@" \s {TRUE, FALSE} to silent messages.");
  271. Console.WriteLine();
  272. }
  273. // ShowDefaults - show defaults for connection variables
  274. public void ShowDefaults() {
  275. Console.WriteLine();
  276. Console.WriteLine("The default Provider is " + provider);
  277. Console.WriteLine();
  278. Console.WriteLine("The default ConnectionString is: ");
  279. Console.WriteLine(" \"" + connectionString + "\"");
  280. Console.WriteLine();
  281. }
  282. // OpenDataSource - open connection to the data source
  283. public void OpenDataSource() {
  284. Console.WriteLine("Attempt to Open...");
  285. switch(provider) {
  286. //case "OLEDB":
  287. // conn = new OleDbConnection();
  288. // break;
  289. case "MYSQL":
  290. conn = new MySqlConnection();
  291. break;
  292. case "POSTGRESCLIENT":
  293. conn = new SqlConnection();
  294. break;
  295. default:
  296. Console.WriteLine("Error: Bad argument or provider not supported.");
  297. break;
  298. }
  299. conn.ConnectionString = connectionString;
  300. try {
  301. conn.Open();
  302. if(conn.State == ConnectionState.Open)
  303. Console.WriteLine("Open was successfully.");
  304. }
  305. catch(Exception e) {
  306. Console.WriteLine("Exception Caught Opening. " + e);
  307. conn = null;
  308. }
  309. }
  310. // CloseDataSource - close the connection to the data source
  311. public void CloseDataSource() {
  312. Console.WriteLine("Attempt to Close...");
  313. try {
  314. conn.Close();
  315. Console.WriteLine("Close was successfull.");
  316. }
  317. catch(Exception e) {
  318. Console.WriteLine("Exeception Caught Closing. " + e);
  319. }
  320. conn = null;
  321. }
  322. // ChangeProvider - change the provider string variable
  323. public void ChangeProvider(string[] parms) {
  324. if(parms.Length == 2) {
  325. string parm = parms[1].ToUpper();
  326. switch(parm) {
  327. case "ORACLECLIENT":
  328. case "ODBC":
  329. case "GDA":
  330. Console.WriteLine("Error: Provider not currently supported.");
  331. break;
  332. case "SQLCLIENT":
  333. provider = "POSTGRESCLIENT";
  334. Console.WriteLine("Warning: Currently, the SqlClient provider is the PostgreSQL provider.");
  335. break;
  336. //case "OLEDB":
  337. case "MYSQL":
  338. case "POSTGRESCLIENT":
  339. provider = parm;
  340. break;
  341. default:
  342. Console.WriteLine("Error: " + "Bad argument or Provider not supported.");
  343. break;
  344. }
  345. Console.WriteLine("Provider: " + provider);
  346. }
  347. else
  348. Console.WriteLine("Error: provider only has one parameter.");
  349. }
  350. // ChangeConnectionString - change the connection string variable
  351. public void ChangeConnectionString(string entry) {
  352. if(entry.Length > 18)
  353. connectionString = entry.Substring(18, entry.Length - 18);
  354. else
  355. connectionString = "";
  356. }
  357. public void SetupInputFile(string[] parms) {
  358. if(parms.Length >= 2) {
  359. Console.WriteLine("Error: wrong number of parameters");
  360. return;
  361. }
  362. inputFilename = parms[1];
  363. // TODO:
  364. // open input file
  365. // while each line, do the SqlSharpCli command or SQL
  366. // close input file
  367. }
  368. public void SetupOutputFile(string[] parms) {
  369. if(parms.Length == 1) {
  370. outputFilename = "";
  371. // TODO: close the output file
  372. }
  373. else if(parms.Length > 2) {
  374. Console.WriteLine("Error: wrong number of parameters");
  375. }
  376. else {
  377. outputFilename = parms[1];
  378. // TODO: open the output file
  379. }
  380. }
  381. public void SetupSilentMode(string[] parms) {
  382. if(parms.Length != 2) {
  383. Console.WriteLine("Error: wrong number of parameters");
  384. return;
  385. }
  386. string parm = parms[1].ToUpper();
  387. if(parm.Equals("TRUE"))
  388. silent = true;
  389. else if(parm.Equals("FALSE"))
  390. silent = false;
  391. else
  392. Console.WriteLine("Error: invalid parameter.");
  393. }
  394. public void OutputLine(string line) {
  395. if(silent == false)
  396. Console.WriteLine(line);
  397. }
  398. public void ExecuteBatch() {
  399. // TODO:
  400. Console.WriteLine("Error: Execution of Batch Commands not implemented yet");
  401. }
  402. // HandleCommand - handle SqlSharpCli commands entered
  403. public void HandleCommand(string entry) {
  404. string[] parms;
  405. // maybe a SQL# Command was found
  406. parms = entry.Split(new char[1] {' '});
  407. string userCmd = parms[0].ToUpper();
  408. switch(userCmd) {
  409. case "\\PROVIDER":
  410. ChangeProvider(parms);
  411. break;
  412. case "\\CONNECTIONSTRING":
  413. ChangeConnectionString(entry);
  414. break;
  415. case "\\OPEN":
  416. OpenDataSource();
  417. break;
  418. case "\\CLOSE":
  419. CloseDataSource();
  420. break;
  421. case "\\S":
  422. SetupSilentMode(parms);
  423. break;
  424. case "\\E":
  425. case "\\EXECUTE":
  426. // Execute SQL Commands or Queries
  427. if(conn == null)
  428. Console.WriteLine("Error: connection is not Open.");
  429. else if(conn.State == ConnectionState.Closed)
  430. Console.WriteLine("Error: connection is not Open.");
  431. else {
  432. if(build == null)
  433. Console.WriteLine("Error: SQL Buffer is empty.");
  434. else {
  435. ExecuteSql(build.ToString());
  436. }
  437. build = null;
  438. }
  439. break;
  440. case "\\F":
  441. // Batch Input File: \f FILENAME
  442. SetupInputFile(parms);
  443. ExecuteBatch();
  444. break;
  445. case "\\O":
  446. // Batch Output File: \o FILENAME
  447. SetupOutputFile(parms);
  448. break;
  449. case "\\H":
  450. case "\\HELP":
  451. // Help
  452. ShowHelp();
  453. break;
  454. case "\\DEFAULTS":
  455. ShowDefaults();
  456. break;
  457. case "\\Q":
  458. case "\\QUIT":
  459. // Quit
  460. break;
  461. default:
  462. // Error
  463. Console.WriteLine("Error: Unknown user command.");
  464. break;
  465. }
  466. }
  467. public void DealWithArgs(string[] args) {
  468. for(int a = 0; a < args.Length; a++) {
  469. if(args[a].Substring(0,1).Equals("-")) {
  470. string arg = args[a].ToUpper().Substring(1, args[a].Length - 1);
  471. switch(arg) {
  472. case "S":
  473. silent = true;
  474. break;
  475. case "F":
  476. if(a + 1 >= args.Length)
  477. Console.WriteLine("Error: Missing FILENAME for -f switch");
  478. else {
  479. inputFilename = args[a + 1];
  480. ExecuteBatch();
  481. }
  482. break;
  483. case "O":
  484. if(a + 1 >= args.Length)
  485. Console.WriteLine("Error: Missing FILENAME for -o switch");
  486. else
  487. outputFilename = args[a + 1];
  488. break;
  489. default:
  490. Console.WriteLine("Error: Unknow switch: " + args[a]);
  491. break;
  492. }
  493. }
  494. }
  495. }
  496. public void Run(string[] args) {
  497. DealWithArgs(args);
  498. string entry = "";
  499. build = null;
  500. if(silent == false) {
  501. Console.WriteLine("Welcome to SQL#. The interactive SQL command-line client ");
  502. Console.WriteLine("for Mono.Data. See http://www.go-mono.com/ for more details.\n");
  503. StartupHelp();
  504. ShowDefaults();
  505. }
  506. while(entry.ToUpper().Equals("\\Q") == false &&
  507. entry.ToUpper().Equals("\\QUIT") == false) {
  508. Console.Write("\nSQL# ");
  509. entry = Console.ReadLine();
  510. Console.WriteLine("Entered: " + entry);
  511. if(entry.Substring(0,1).Equals("\\")) {
  512. HandleCommand(entry);
  513. }
  514. else if(entry.IndexOf(";") >= 0) {
  515. // most likely the end of SQL Command or Query found
  516. // execute the SQL
  517. if(conn == null)
  518. Console.WriteLine("Error: connection is not Open.");
  519. else if(conn.State == ConnectionState.Closed)
  520. Console.WriteLine("Error: connection is not Open.");
  521. else {
  522. if(build == null) {
  523. build = new StringBuilder();
  524. }
  525. build.Append(entry);
  526. ExecuteSql(build.ToString());
  527. build = null;
  528. }
  529. }
  530. else {
  531. // most likely a part of a SQL Command or Query found
  532. // append this part of the SQL
  533. if(build == null) {
  534. build = new StringBuilder();
  535. }
  536. build.Append(entry + " ");
  537. }
  538. }
  539. }
  540. }
  541. public class SqlSharpDriver {
  542. public static void Main(string[] args) {
  543. SqlSharpCli sqlCommandLineEngine = new SqlSharpCli();
  544. sqlCommandLineEngine.Run(args);
  545. }
  546. }
  547. }