DBHelper.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208
  1. using System.Collections;
  2. using System.Data;
  3. using System.Data.Common;
  4. using System.Data.SqlClient;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using System.Xml;
  8. namespace com.cloudsoft.utils
  9. {
  10. /// <summary>
  11. /// Class contains methods for performing database queries
  12. /// </summary>
  13. public class DBHelper
  14. {
  15. private Boolean _pbUppercaseNodes = false;
  16. private String _pzDateFormat = "dd-MMM-yyyy HH:mm:ss";
  17. private String pzSystem = "";
  18. private String pzSchema = "";
  19. private XMLHelper _request = null;
  20. private Boolean lbAutoCommit = true;
  21. private DbConnection oConnection = null;
  22. private ArrayList _aParser = null;
  23. private DBParams _Command = null;
  24. public DBHelper(XMLHelper oRequest)
  25. {
  26. lbAutoCommit = (oRequest._con == null);
  27. _request = oRequest;
  28. pzSystem = oRequest.getString("system");
  29. oConnection = oRequest._con;
  30. }
  31. /// <summary>
  32. /// Creates, opens, and returns a connection to the database using details specified in the registry
  33. /// with the name stored in the local pzSystem variable.
  34. /// </summary>
  35. /// <param name="bIsRecordSet">If true then PLSQLRSet=1 is added to the connection string.</param>
  36. /// <param name="bDbConnection">Whether to create an DbConnection or a standard DbConnection.</param>
  37. /// <returns>An DbConnection.</returns>
  38. private DbConnection getConnection()
  39. {
  40. DbConnection cn;
  41. string zConnString = "Server=localhost,1435;Database=AlexisPTSTest;User Id=gpspl;Password=yW2S6KXdY8;";
  42. //String zConnString = ConfigurationManager.ConnectionStrings[pzSystem].ConnectionString;
  43. cn = new SqlConnection(zConnString);
  44. try
  45. {
  46. cn.Open();
  47. }
  48. catch (Exception ex)
  49. {
  50. throw ex;
  51. }
  52. return cn;
  53. }
  54. //For File Loader ends here
  55. #region Public Methods
  56. /// <summary>Creates a new instance of DBHelper for a given system,
  57. /// defaulting to the default data provider</summary>
  58. /// <param name="zSystem">The system to connect to</param>
  59. /// <remarks>
  60. /// A registry entry should be set up for the given system under Hkey/LocalMachine/Software/GlaxoWellcome/system
  61. /// The system should have a minimum of the following:
  62. /// <list type="bullet">
  63. /// <item><description>DBUser</description></item>
  64. /// <item><description>DBPassword</description></item>
  65. /// <item><description>DBSource</description></item>
  66. /// </list>
  67. ///</remarks>
  68. public DBHelper(String zSystem)
  69. {
  70. pzSystem = zSystem.ToUpper();
  71. }
  72. public DBHelper(String zSystem, Boolean bUppercaseNodes) : this(zSystem)
  73. {
  74. _pbUppercaseNodes = bUppercaseNodes;
  75. }
  76. public DBHelper(String zSystem, Boolean bUppercaseNodes, String zDateFormat) : this(zSystem, bUppercaseNodes)
  77. {
  78. _pzDateFormat = zDateFormat;
  79. }
  80. /// <summary>
  81. /// Creates Parameters to pass to the passed in Command type
  82. /// </summary>
  83. /// <param name="zCommandText">Can be either a SQL Command or a stored procedure depending on the type</param>
  84. /// <param name="tCommandType">The type of Command to create parameters for</param>
  85. /// <returns>The Parameters Object</returns>
  86. public DBParams createSPParams(String zSQL)
  87. {
  88. return createSPParams(zSQL, "");
  89. }
  90. public DBParams createSPParams(String zSQL, XMLHelper oNode)
  91. {
  92. _request = oNode;
  93. zSQL = parseSQL(zSQL);
  94. if (_Command != null && _Command.Command != null)
  95. _Command.Command.Connection.Close();
  96. DbCommand oCommand = getConnection().CreateCommand();
  97. oCommand.CommandText = zSQL;
  98. _Command = new DBParams(oCommand);
  99. addParserParams(oNode);
  100. return _Command;
  101. }
  102. public DBParams createSPParams(String zSQL, String zXPath)
  103. {
  104. if (_request != null)
  105. zSQL = parseSQL(zSQL);
  106. if (_Command != null && _Command.Command != null)
  107. _Command.Command.Connection.Close();
  108. DbCommand oCommand = getConnection().CreateCommand();
  109. oCommand.CommandText = zSQL;
  110. _Command = new DBParams(oCommand);
  111. if (zXPath.Equals(""))
  112. addParserParams();
  113. else
  114. addParserParams(zXPath);
  115. return _Command;
  116. }
  117. public String parseSQL(String zSQL)
  118. {
  119. _aParser = new ArrayList();
  120. return parseSQL(zSQL, false);
  121. }
  122. public String parseSQL(String zSQL, Boolean bConditional)
  123. {
  124. try
  125. {
  126. //Make sure square brackets are even
  127. int iEven = 0;
  128. for(int i = 0, n = zSQL.Length ; i < n ; i++)
  129. {
  130. char c = zSQL[i];
  131. if (c == '[') iEven++;
  132. if (c == ']') iEven--;
  133. }
  134. if (iEven != 0)
  135. {
  136. throw new Exception("Square brackets must be matched");
  137. }
  138. // Find optional clauses
  139. Regex regex = new Regex("\\[([^\\[\\]]+|\\[([^\\[\\]]+|\\[([^\\[\\]]+)*\\])*\\])*\\]");
  140. Match matcher = regex.Match(zSQL);
  141. int iCurr = 0;
  142. StringBuilder sb = new StringBuilder();
  143. while (matcher.Success)
  144. {
  145. sb.Append(replaceSQLVars(zSQL.Substring(iCurr, matcher.Index - iCurr), bConditional));
  146. //iCurr = matcher.start() + matcher.end();
  147. iCurr = matcher.Index + matcher.Length;
  148. String match = matcher.Groups[0].Value;
  149. match = match.Substring(1, match.Length - 2);
  150. if (matcher.Groups[2].Value != null)
  151. sb.Append(parseSQL(match,true));
  152. else
  153. sb.Append(replaceSQLVars(match, true));
  154. matcher = matcher.NextMatch();
  155. }
  156. sb.Append(replaceSQLVars(zSQL.Substring(iCurr), bConditional));
  157. return sb.ToString();
  158. }
  159. catch (Exception ex)
  160. {
  161. return "";
  162. }
  163. }
  164. private String replaceSQLVars(String zSQL, Boolean bConditional)
  165. {
  166. try
  167. {
  168. // Find variables to replace
  169. Regex regex = new Regex("[vilcbotdf]?:[@a-z_0-9./]*");
  170. Match matcher = regex.Match(zSQL);
  171. StringBuilder sb = new StringBuilder();
  172. int iCurr = 0;
  173. while (matcher.Success)
  174. {
  175. // Get the replace value
  176. String match = matcher.Groups[0].Value;
  177. String zMatch = match.Substring(match.IndexOf(':')+1);
  178. char zMatchType = match[0];
  179. // If this is a conditional replace return nothing as soon as a variable is empty
  180. //if (bConditional && _request.getString(zMatch) == "" && zMatchType != 'o')
  181. if (bConditional && _request.getString(zMatch).Equals(""))
  182. return "";
  183. String zTextBefore = zSQL.Substring(iCurr, matcher.Index - iCurr);
  184. String zReplace = "";
  185. switch (zMatchType)
  186. {
  187. case ':':
  188. case 'o': zReplace = _request.getString(zMatch);
  189. //if (zReplace == "") zReplace = "=";
  190. if (zReplace.Equals("soundex"))
  191. {
  192. String[] arrWords = zTextBefore.Split(' ');
  193. zReplace += "(" + arrWords[arrWords.Length-1] + ") = ";
  194. zTextBefore = "";
  195. for (int i = 0; i < arrWords.Length - 1; i++)
  196. zTextBefore += arrWords[i] + " ";
  197. }
  198. break;
  199. case 'i':
  200. case 'f':
  201. case 't':
  202. case 'd':
  203. case 'b':
  204. zReplace = $"@{zMatch}";
  205. _aParser.Add(match);
  206. break;
  207. default:
  208. zReplace = $"@{zMatch}"; ;
  209. String zOp = _request.getString("op_" + zMatch);
  210. if (zOp.Equals("soundex"))
  211. zReplace = "soundex('" + zReplace + "')";
  212. else if (zOp.Equals("like"))
  213. match = "l:" + zMatch;
  214. _aParser.Add(match);
  215. break;
  216. }
  217. sb.Append(zTextBefore);
  218. iCurr = matcher.Index + matcher.Length;
  219. sb.Append(zReplace);
  220. matcher = matcher.NextMatch();
  221. }
  222. sb.Append(zSQL.Substring(iCurr));
  223. return sb.ToString();
  224. }
  225. catch (Exception ex)
  226. {
  227. return "";
  228. }
  229. }
  230. private void addParserParams()
  231. {
  232. addParserParams(_request);
  233. }
  234. private void addParserParams(String zXPath)
  235. {
  236. foreach (XMLHelper oNode in _request.getNodes(zXPath))
  237. {
  238. addParserParams(oNode);
  239. //_Command.addBatch();
  240. }
  241. }
  242. private void addParserParams(XMLHelper oNode)
  243. {
  244. if (_aParser is null)
  245. return;
  246. for (int i=0; i < _aParser.Count; i++)
  247. {
  248. // Get the replace value
  249. String match = _aParser[i] as string;
  250. String zMatch = match.Substring(match.IndexOf(':')+1);
  251. char zMatchType = match[0];
  252. Object oParam = null;
  253. String zValue = (zMatch.Equals("xml_data")) ? oNode.getNode(zMatch).getFirstChild().getXML() : oNode.getString(zMatch);
  254. DbType iType = DbType.String;
  255. switch (zMatchType)
  256. {
  257. case 'f': oParam = oNode.getDouble(zMatch);
  258. iType = DbType.Decimal;
  259. break;
  260. case 'i': oParam = oNode.getInt(zMatch);
  261. iType = DbType.Int32;
  262. break;
  263. case 't': oParam = oNode.getSQLDateTime(zMatch);
  264. iType = DbType.DateTime;
  265. break;
  266. case 'd': oParam = oNode.getSQLDate(zMatch);
  267. iType = DbType.Date;
  268. break;
  269. case 'b': oParam = (oNode.getBoolean(zMatch)) ? "Y" : "N";
  270. zValue = (String) oParam;
  271. iType = DbType.Boolean;
  272. break;
  273. case 'c': oParam = zValue;
  274. iType = DbType.String;
  275. break;
  276. case 'l': oParam = "%" + zValue + "%";
  277. zValue = (String) oParam;
  278. break;
  279. default: oParam = zValue;
  280. break;
  281. }
  282. if (zValue.Length == 0)
  283. oParam = null;
  284. _Command.set($"@{zMatch}", oParam, iType);
  285. }
  286. }
  287. /// <summary>
  288. /// Legacy method - now superseded by createDBSPParams
  289. /// </summary>
  290. public DBParams createSPParams(String zCommandText, CommandType tCommandType)
  291. {
  292. DbCommand oCommand = getConnection().CreateCommand();
  293. oCommand.CommandType = tCommandType;
  294. oCommand.CommandText = zCommandText;
  295. return new DBParams(oCommand);
  296. }
  297. /// <summary>
  298. /// Executes a store procedure optionally returning output parameters
  299. /// This is not used for returning recordsets as XML, but for transactional stored procedures
  300. /// </summary>
  301. /// <param name="oParams">DBParams Parameters</param>
  302. /// <returns>An XMLHelper with any output parameters</returns>
  303. public XMLHelper execute(DBParams oParams)
  304. {
  305. //return execute(oParams, false);
  306. return execute(oParams, false);
  307. }
  308. /// <summary>
  309. /// Executes a SQL Query
  310. /// This is not used for returning recordsets as XML, but for transactional stored procedures
  311. /// </summary>
  312. /// <param name="zSQL">DBParams Parameters</param>
  313. /// <returns>An XMLHelper with any output parameters</returns>
  314. public XMLHelper execute(String zSQL)
  315. {
  316. DBParams oParams = createSPParams(zSQL, CommandType.Text);
  317. return execute(oParams, false);
  318. }
  319. /// <summary>
  320. /// Executes a store procedure optionally returning output parameters
  321. /// This is not used for returning recordsets as XML, but for transactional stored procedures
  322. /// </summary>
  323. /// <param name="oParams">DBParams Parameters</param>
  324. /// <returns>An XMLHelper with any output parameters</returns>
  325. public XMLHelper execute(DBParams oParams, Boolean bKeepOpen)
  326. {
  327. return executeODAC(oParams, bKeepOpen);
  328. }
  329. #endregion
  330. #region ODAC Specific Private Methods
  331. /// <summary>
  332. /// Executes a store procedure optionally returning output parameters
  333. /// This is not used for returning recordsets as XML, but for transactional stored procedures
  334. /// </summary>
  335. /// <param name="oParams">DBParams Parameters</param>
  336. /// <param name="bKeepOpen">Flag to determine if the connection is kept open or not</param>
  337. /// <returns>An XMLHelper with any output parameters</returns>
  338. private XMLHelper executeODAC(DBParams oParams, Boolean bKeepOpen)
  339. {
  340. DateTime dStart = DateTime.Now;
  341. XMLHelper oResponse = new XMLHelper("response");
  342. oResponse.appendNode("rows", Convert.ToString(oParams.ExecuteNonQuery()));
  343. foreach (DbParameter oParam in oParams.ODACParameters())
  344. {
  345. if (oParam.Direction == System.Data.ParameterDirection.Output)
  346. {
  347. oResponse.appendNode(oParam.ParameterName.Replace(":", ""), oParam.Value.ToString());
  348. }
  349. }
  350. TimeSpan tDiff = DateTime.Now.Subtract(dStart);
  351. oResponse.appendAttribute("duration", tDiff.TotalMilliseconds.ToString());
  352. if (!bKeepOpen)
  353. {
  354. oParams.CloseConnection();
  355. oParams.CloseCommand();
  356. }
  357. return oResponse;
  358. }
  359. /// <summary>
  360. /// Creates Parameters to pass to a Stored Procedure. Also calls getConnection to get an
  361. /// DbConnection, and appends the required RefCursor.
  362. /// </summary>
  363. /// <param name="zCommandText">The stored procedure to be called</param>
  364. /// <returns>The Parameters Object</returns>
  365. /// <example>
  366. /// DBHelper oDB = new DBHelper("uki");
  367. /// DBParams oCommand = oDB.createOracleSPParams("pkg_orgcusts.RetrieveTargetOrgsByBrand");
  368. /// </example>
  369. private DBParams createODACSPParams(String zCommandText, CommandType tCommandType, Boolean bindByName)
  370. {
  371. DbCommand oCommand = getConnection().CreateCommand();
  372. oCommand.CommandType = tCommandType;
  373. switch (tCommandType)
  374. {
  375. case CommandType.Text:
  376. {
  377. oCommand.CommandText = zCommandText;
  378. break;
  379. }
  380. case CommandType.StoredProcedure:
  381. case CommandType.TableDirect:
  382. {
  383. oCommand.CommandText = pzSchema + "." + zCommandText;
  384. break;
  385. }
  386. }
  387. return new DBParams(oCommand);
  388. }
  389. #endregion
  390. public void closeConnection(DBParams oCommand)
  391. {
  392. oCommand.CloseConnection();
  393. }
  394. #region Overrides for Get Dom
  395. public XMLHelper getDOM(IDataReader oRS)
  396. {
  397. return getDOM(oRS, 0, 2000);
  398. }
  399. /// <summary>
  400. /// Gets a DOM of a recordset
  401. /// </summary>
  402. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  403. /// <returns>An XMLHelper representation of the recordset in the format response/rows/row</returns>
  404. public XMLHelper getDOM(IDataReader oRS, int iStartRow, int iMaxRows)
  405. {
  406. return appendToDOM(null, null, null, null, oRS, "rows", "row", iStartRow, iMaxRows, true, RefCurPosition.First, false, true, false);
  407. }
  408. /// <summary>
  409. /// Gets a DOM of a recordset
  410. /// </summary>
  411. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  412. /// <returns>An XMLHelper representation of the recordset in the format response/rows/row</returns>
  413. public XMLHelper getDOM(String zSQL)
  414. {
  415. _Command = createSPParams(zSQL);
  416. return getDOM(_Command, "rows", "row");
  417. }
  418. /// <summary>
  419. /// Gets a DOM of a recordset
  420. /// </summary>
  421. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  422. /// <returns>An XMLHelper representation of the recordset in the format response/rows/row</returns>
  423. public XMLHelper getDOM(DBParams oCommand, String zRowsetName, String zRowName)
  424. {
  425. return getDOM(oCommand, 0, 0, false, RefCurPosition.First, zRowsetName, zRowName, false, true, null, null, null, null, false);
  426. }
  427. /// <summary>
  428. /// Gets a DOM of a recordset
  429. /// </summary>
  430. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  431. /// <returns>An XMLHelper representation of the recordset in the format response/rows/row</returns>
  432. public XMLHelper getDOM(DBParams oCommand, Boolean withRefCur)
  433. {
  434. RefCurPosition refCurPosition = RefCurPosition.None;
  435. if (withRefCur)
  436. refCurPosition = RefCurPosition.First;
  437. return getDOM(oCommand, 0, 0, false, refCurPosition, "rows", "row", false, true, null, null, null, null, false);
  438. }
  439. /// <summary>
  440. /// Gets a XML DOM of a recordset
  441. /// </summary>
  442. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  443. /// <param name="iStartRow">The start row number to retrieve</param>
  444. /// <param name="iMaxRows">The maximum number of rows</param>
  445. /// <param name="bShowTotal">Determines whether the total Rowcount is shown.</param>
  446. /// <param name="zRowsetName">The Rowset node name.</param>
  447. /// <param name="zRowName">The Row node name</param>
  448. /// <param name="bShowMetadata">Determines whether to create meta data info</param>
  449. /// <returns>An XMLHelper representation of the recordset</returns>
  450. public XMLHelper getDOM(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, DBHelper.RefCurPosition refCurPosition,
  451. String zRowsetName, String zRowName, Boolean bShowMetadata, Boolean bCloseConnection,
  452. XMLHelper oInputDOM, String zNode, String zKey, String zGrouping, Boolean CheckRowName)
  453. {
  454. //Time the processing...
  455. DateTime dStart = DateTime.Now;
  456. //Execute the database Command...
  457. XMLHelper oResponse = appendToDOM(oInputDOM, zNode, zKey, zGrouping, oCommand, zRowsetName, zRowName, iStartRow, iMaxRows, bShowTotal, refCurPosition, bShowMetadata, false, CheckRowName);
  458. //Add the execution time to the ouptut...
  459. TimeSpan tDiff = DateTime.Now.Subtract(dStart);
  460. oResponse.appendAttribute("duration", tDiff.TotalMilliseconds.ToString());
  461. //Close the connection if required...
  462. if (bCloseConnection)
  463. {
  464. oCommand.CloseConnection();
  465. }
  466. return oResponse;
  467. }
  468. #endregion
  469. #region Overrides for Append To DOM
  470. /// <summary>
  471. /// Executes a Command and adds the recordset to an existing DOM
  472. /// </summary>
  473. /// <param name="oInputDom">Dom to append to</param>
  474. /// <param name="zNode">Xpath to the node to append information to</param>
  475. /// <param name="zKey">Key to match</param>
  476. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  477. /// <param name="zRowsetName">The Rowset node name</param>
  478. /// <param name="zRowName">The row Node Name</param>
  479. public void appendToDOM(XMLHelper oInputDom, String zNode, String zKey, DBParams oCommand, String zRowsetName, String zRowName)
  480. {
  481. appendToDOM(oInputDom, zNode, zKey, null, oCommand, zRowsetName, zRowName, 0, 9999999,
  482. false, (oCommand.Command.CommandType == CommandType.Text ? RefCurPosition.None : RefCurPosition.First), false, false, false);
  483. //appendToDOM(oInputDom, zNode, zKey, oCommand, zRowsetName, zRowName, 0, 9999999, false, false);
  484. }
  485. /// <summary>
  486. /// Executes a Command and adds the recordset to an existing DOM
  487. /// </summary>
  488. /// <param name="oInputDom">Dom to append to</param>
  489. /// <param name="zNode">Xpath to the node to append information to</param>
  490. /// <param name="zKey">Key to match</param>
  491. /// <param name="oParams">Parameters to pass to the stored procedure</param>
  492. /// <param name="zRowsetName">The Rowset node name</param>
  493. /// <param name="zRowName">The row Node Name</param>
  494. /// <param name="iStartRow">The start row number</param>
  495. /// <param name="iMaxRows">The maximun number of rows to fetch</param>
  496. /// <param name="bShowTotal">Determines whether totals are shown</param>
  497. /// <param name="bShowMetadata">Determines whether metadata is to be shown</param>
  498. ///
  499. public void appendToDOM(XMLHelper oInputDom, String zNode, String zKey, DBParams oParams, String zRowsetName, String zRowName, int iStartRow, int iMaxRows, Boolean bShowTotal, Boolean bShowMetadata)
  500. {
  501. appendToDOM(oInputDom, zNode, zKey, null, oParams, zRowsetName, zRowName, iStartRow, iMaxRows,
  502. bShowTotal, RefCurPosition.None, false, false, false);
  503. }
  504. /// <summary>
  505. /// Executes a Command and adds the recordset to an existing DOM
  506. /// JF 12/2007 - Generalised to take an IDbCommand, allowing it to be used with either an
  507. /// DbCommand or DbCommand
  508. /// </summary>
  509. /// <param name="oInputDom">Dom to append to</param>
  510. /// <param name="zNode">Xpath to the node to append information to</param>
  511. /// <param name="zKey">Key to match</param>
  512. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  513. /// <param name="zRowsetName">The Rowset node name</param>
  514. /// <param name="zRowName">The row Node Name</param>
  515. /// <param name="iStartRow">The start row number</param>
  516. /// <param name="iMaxRows">The maximun number of rows to fetch</param>
  517. /// <param name="bShowTotal">Determines whether totals are shown</param>
  518. /// <param name="bShowMetadata">Determines whether metadata is to be shown</param>
  519. /// <param name="bCloseConnection">Whether to close the Commands connection when finished exection</param>
  520. /// <param name="CheckRowName">This is an override to force a check of the row name against any xpath which
  521. /// may have been defined in the column name from the procedure/package. It's function is to avoid the creation
  522. /// of a dom structure such as rows/row/row if the xpath in the procedure reads row/@value. If the first component
  523. /// of the xpath in the procedure matches the rowname specified in the call to this method, then it will assume
  524. /// that you don't want to append a new child with the same name. It will still allow the creation of
  525. /// rows/row/childrow if the procedure reads childrow/@value.</param>
  526. public XMLHelper appendToDOM(XMLHelper oInputDom, String zNode, String zKey, String zGrouping, DBParams oParams,
  527. String zRowsetName, String zRowName, int iStartRow, int iMaxRows,
  528. Boolean bShowTotal, DBHelper.RefCurPosition refCurPosition, Boolean bShowMetadata, Boolean bCloseConnection,
  529. Boolean CheckRowName)
  530. {
  531. #region Execute the database Command
  532. //Execute the Command and obtain the output recordset...
  533. DbCommand oCommand = oParams.AsDbCommand();
  534. //oCommand.Prepare();
  535. CommandBehavior cb = CommandBehavior.Default;
  536. if (bCloseConnection)
  537. {
  538. cb = CommandBehavior.CloseConnection;
  539. }
  540. IDataReader oRS = oCommand.ExecuteReader(cb);
  541. #endregion
  542. //Return the response (the input dom may also have been appended to inline)...
  543. return appendToDOM(oInputDom, zNode, zKey, zGrouping, oRS, zRowsetName, zRowName, iStartRow, iMaxRows, bShowTotal, refCurPosition, bShowMetadata, bCloseConnection, CheckRowName);
  544. }
  545. public XMLHelper appendToDOM(XMLHelper oInputDom, String zNode, String zKey, String zGrouping, IDataReader oRS,
  546. String zRowsetName, String zRowName, int iStartRow, int iMaxRows,
  547. Boolean bShowTotal, DBHelper.RefCurPosition refCurPosition, Boolean bShowMetadata, Boolean bCloseConnection,
  548. Boolean CheckRowName)
  549. {
  550. //Establish output vars...
  551. XMLHelper oResponse = new XMLHelper("response");
  552. //XMLHelper oResponse = (oInputDom == null || oInputDom.getName() == "request") ? new XMLHelper("response") : oInputDom;
  553. XMLHelper oInRowGroup = null;
  554. XMLHelper oOutRowGroup = null;
  555. XMLHelper oRow = null;
  556. String zNodeValue;
  557. Int32 lFields = oRS.FieldCount;
  558. String[] vValue = null;
  559. Int32 lGroupCols = 0;
  560. String zGroupNode = null;
  561. if (zGrouping != "" && zGrouping != null)
  562. {
  563. vValue = zGrouping.Split(":".ToCharArray());
  564. lGroupCols = Convert.ToInt32(vValue[0]);
  565. zGroupNode = vValue[1];
  566. }
  567. //Determine whether to create a grouping node...
  568. if (zRowsetName != "" && zRowsetName != null)
  569. {
  570. //Append a grouping node to the response to hold child nodes...
  571. oOutRowGroup = oResponse.appendNode(zRowsetName);
  572. }
  573. else
  574. {
  575. //Appending child nodes directly to the response root, rather than a grouping node...
  576. oOutRowGroup = oResponse;
  577. }
  578. // Create a collection of keys in the DOM
  579. Dictionary<String, XMLHelper> oColKeys = new Dictionary<String, XMLHelper>();
  580. if (zNode != "" && zNode != null)
  581. {
  582. XMLHelper[] oNodes = oInputDom.getNodes(zNode);
  583. for (int i = 0; i < oNodes.Length; i++)
  584. {
  585. XMLHelper oNode = oNodes[i];
  586. if (zRowsetName != "" && zRowsetName != null)
  587. {
  588. oInRowGroup = oNode.appendNode(zRowsetName);
  589. }
  590. else
  591. {
  592. oInRowGroup = oNode;
  593. }
  594. if (zKey != "" && zKey != null)
  595. oColKeys.Add(oNodes[i].getValue(zKey), oInRowGroup);
  596. }
  597. }
  598. //If you are required to append "Metadata", then
  599. //append column names and types...
  600. if (bShowMetadata)
  601. {
  602. XMLHelper oMeta = oResponse.appendNode("meta_data");
  603. XMLHelper oCols = oMeta.appendNode("columns");
  604. for (int i = 0; i < oRS.FieldCount; i++)
  605. {
  606. XMLHelper oNode = oCols.appendNode("column");
  607. oNode.appendAttribute("name", oRS.GetName(i).ToLower());
  608. oNode.appendAttribute("type", oRS.GetDataTypeName(i));
  609. }
  610. }
  611. #region Deal with paging
  612. // Set the start row and max rows. Unless maxrows has been explicitly
  613. //defined then default to a safe value (2000 in this case)...
  614. int iRow = iStartRow;
  615. if (iMaxRows == 0)
  616. iMaxRows = Int32.MaxValue;
  617. //iMaxRows = 2000;
  618. //If you are "paging", then a startrow will be provided, so
  619. //advance to the startrow of this page...
  620. if (iStartRow > 0)
  621. {
  622. for (int i = 0; i < iStartRow; i++)
  623. oRS.Read();
  624. }
  625. #endregion
  626. String zCurrRowKey = null;
  627. String zPrevRowKey = null;
  628. Boolean bFirst = true;
  629. XMLHelper oTempNode = null;
  630. Int32 lField = 0;
  631. // Loop through the recordset and construct the XML DOM
  632. while (oRS.Read() && iRow < (iMaxRows + iStartRow))
  633. {
  634. if (iRow >= iStartRow)
  635. {
  636. bFirst = true;
  637. // Get the "Key" for this row. Used to determine whether this should be a new grouping.
  638. zCurrRowKey = null;
  639. for (lField = 0; lField <= lGroupCols - 1; lField++)
  640. {
  641. zCurrRowKey += (string)oRS[lField].ToString() + "-";
  642. }
  643. if (!string.IsNullOrEmpty(zKey))
  644. {
  645. oInRowGroup = oColKeys[oRS[0].ToString()];
  646. }
  647. //If you aren't grouping, or if this key is new...
  648. if (lGroupCols == 0 || zCurrRowKey != zPrevRowKey)
  649. {
  650. //Create a new node...
  651. oRow = new XMLHelper(zRowName);
  652. if (oInRowGroup != null)
  653. {
  654. oRow = oInRowGroup.appendNode(oRow);
  655. }
  656. oTempNode = oRow;
  657. }
  658. lField = 0;
  659. for (int i = 0; i < oRS.FieldCount; i++)
  660. {
  661. //DataRow oField = oRS.[i];
  662. if (lField >= lGroupCols || zCurrRowKey != zPrevRowKey)
  663. {
  664. //vValue = oField.Value;
  665. zNodeValue = "";
  666. // Get the data from the field
  667. if (oRS.GetFieldType(i).Name =="DateTime")
  668. {
  669. if (oRS.IsDBNull(i))
  670. zNodeValue = "";
  671. else
  672. zNodeValue = oRS.GetDateTime(i).ToString(_pzDateFormat);
  673. }
  674. else
  675. {
  676. if (oRS.IsDBNull(i))
  677. zNodeValue = "";
  678. else
  679. zNodeValue = oRS[i].ToString();
  680. }
  681. String zNodeName = oRS.GetName(i).ToLower().Replace("\"", "");
  682. if (_pbUppercaseNodes)
  683. zNodeName = zNodeName.ToUpper();
  684. //This is an override to check the row name during an append.
  685. //See procedure definition comment for an explanation...
  686. if (CheckRowName && zNodeName.Split("/".ToCharArray()).Length > 1)
  687. {
  688. if (zRowName == zNodeName.Split("/".ToCharArray())[0])
  689. zNodeName = zNodeName.Replace(zRowName + "/", "");
  690. }
  691. // Add the field to the current row
  692. if (bFirst & !string.IsNullOrEmpty(zKey))
  693. {
  694. //Do Nothing...
  695. }
  696. else if (lGroupCols == lField & lGroupCols > 0)
  697. {
  698. oRow = oRow.appendNode(zGroupNode);
  699. oRow.appendXPathNode(zNodeName, zNodeValue, false);
  700. }
  701. else
  702. {
  703. //if this is a value node rather than an attribute,
  704. //and if it is a match to the node name...
  705. if (CheckRowName &&
  706. (zNodeName == zRowName) &&
  707. !zNodeName.Contains("@")
  708. )
  709. {
  710. //Just set the node value...
  711. oRow.setValue(zNodeValue);
  712. }
  713. else
  714. {
  715. if (zNodeName == "xml-data" || zNodeName.EndsWith("_xml"))
  716. oRow.appendNode(new XMLHelper("<" + zNodeName + ">" + zNodeValue + "</" + zNodeName + ">"));
  717. else
  718. oRow.appendXPathNode(zNodeName, zNodeValue, false);
  719. }
  720. }
  721. }
  722. bFirst = false;
  723. lField = lField + 1;
  724. }
  725. oRow = oTempNode;
  726. //If you are dom merging, append to the inrowgroup...
  727. //if (oInRowGroup != null)
  728. // oInRowGroup.appendNode(oRow);
  729. //Always append to the outrowgroup...
  730. oOutRowGroup.appendNode(oRow);
  731. zPrevRowKey = zCurrRowKey;
  732. }
  733. iRow++;
  734. }
  735. // If total is to be shown move to the end of the recordset
  736. if (bShowTotal)
  737. {
  738. //Need to read the remaining rows in the recordset to count rows...
  739. bool additionalRowsCounted = false;
  740. while (oRS.Read() && iRow < 2000)
  741. {
  742. additionalRowsCounted = true;
  743. iRow++;
  744. }
  745. //if ((iStartRow == 0) && (additionalRowsCounted))
  746. // iRow++;
  747. //if (iStartRow > 0)
  748. // iRow--;
  749. if (additionalRowsCounted)
  750. iRow++;
  751. //Append the rowcount to the returned results...
  752. oResponse.appendAttribute("total_rows", Convert.ToString(iRow));
  753. //oResponse.appendNode("total_rows", Convert.ToString(iRow));
  754. }
  755. //Always close the recordset...
  756. oRS.Close();
  757. //Return the response (the input dom may also have been appended to inline)...
  758. return oResponse;
  759. }
  760. public XMLHelper getTables()
  761. {
  762. XMLHelper oResponse = null;
  763. try
  764. {
  765. DataTable dt = getConnection().GetSchema("Tables");
  766. oResponse = getDOM(dt);
  767. }
  768. catch (Exception ex)
  769. {
  770. }
  771. return oResponse;
  772. }
  773. public XMLHelper getColumns(String zTable)
  774. {
  775. XMLHelper oResponse = null;
  776. try
  777. {
  778. DbCommand cmd = getConnection().CreateCommand();
  779. cmd.CommandText = "select * from " + zTable;
  780. IDataReader rs = cmd.ExecuteReader();
  781. oResponse = getDOM(rs.GetSchemaTable());
  782. }
  783. catch (Exception ex)
  784. {
  785. }
  786. return oResponse;
  787. }
  788. public XMLHelper getDOM(DataTable dt)
  789. {
  790. XMLHelper oResponse = new XMLHelper("response");
  791. XMLHelper oRows = oResponse.appendNode("rows");
  792. foreach (DataRow dr in dt.Rows)
  793. {
  794. XMLHelper oRow = oRows.appendNode("row");
  795. foreach (DataColumn dc in dt.Columns)
  796. {
  797. oRow.appendNode(dc.ColumnName.ToLower(), dr[dc].ToString());
  798. }
  799. }
  800. return oResponse;
  801. }
  802. #endregion
  803. #region Overrides for Get XML
  804. public enum RefCurPosition
  805. {
  806. First,
  807. Last,
  808. None
  809. }
  810. /// <summary>
  811. /// Gets an XML String of a recordset
  812. /// </summary>
  813. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  814. /// <returns>An XML string representation of the recordset in the format response/rows/row</returns>
  815. public String getXML(DBParams oCommand)
  816. {
  817. return getDOM(oCommand, true).getXML();
  818. }
  819. public String getXML(DBParams oCommand, Boolean withRefCur)
  820. {
  821. return getDOM(oCommand, withRefCur).getXML();
  822. }
  823. /// <summary>
  824. /// Gets an XML String of a recordset
  825. /// </summary>
  826. /// <param name="oCommand">Parameters to pass to the stored procedure</param>
  827. /// <param name="iStartRow">The start row number to retrieve</param>
  828. /// <param name="iMaxRows">The maximum number of rows</param>
  829. /// <param name="bShowTotal">Determines whether the total Rowcount is shown.</param>
  830. /// <param name="zRowsetName">The Rowset node name.</param>
  831. /// <param name="zRowName">The Row node name</param>
  832. /// <param name="bShowMetadata">Determines whether to create meta data info</param>
  833. /// <returns>An XML string representation of the recordset</returns>
  834. public String getXML(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, String zRowsetName, String zRowName, Boolean bShowMetadata)
  835. {
  836. return getXML(oCommand, iStartRow, iMaxRows, bShowTotal, zRowsetName, zRowName, bShowMetadata, true);
  837. }
  838. public XMLHelper getXMLHelper(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, String zRowsetName, String zRowName, Boolean bShowMetadata)
  839. {
  840. return getXMLHelper(oCommand, iStartRow, iMaxRows, bShowTotal, zRowsetName, zRowName, bShowMetadata, true);
  841. }
  842. public String getXML(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, String zRowsetName, String zRowName, Boolean bShowMetadata, Boolean bCloseConnection)
  843. {
  844. return getXML(oCommand, iStartRow, iMaxRows, bShowTotal, RefCurPosition.First, zRowsetName, zRowName, bShowMetadata, bCloseConnection, null, null, null, null, false).getXML();
  845. }
  846. public XMLHelper getXMLHelper(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, String zRowsetName, String zRowName, Boolean bShowMetadata, Boolean bCloseConnection)
  847. {
  848. return getXML(oCommand, iStartRow, iMaxRows, bShowTotal, RefCurPosition.First, zRowsetName, zRowName, bShowMetadata, bCloseConnection, null, null, null, null, false);
  849. }
  850. public XMLHelper getXML(DBParams oCommand, int iStartRow, int iMaxRows, Boolean bShowTotal, DBHelper.RefCurPosition refCurPosition, String zRowsetName, String zRowName, Boolean bShowMetadata, Boolean bCloseConnection, XMLHelper oInputDOM, String zNode, String zKey, String zGrouping, Boolean CheckRowName)
  851. {
  852. return getDOM(oCommand, iStartRow, iMaxRows, bShowTotal, refCurPosition, zRowsetName, zRowName, bShowMetadata, bCloseConnection, oInputDOM, zNode, zKey, zGrouping, CheckRowName);
  853. }
  854. /// <summary>
  855. /// High performance version of append to dom.
  856. /// Will always add columns as attributes.
  857. /// </summary>
  858. public String getXML(DBParams oParams, String zRowsetName, String zRowName, Boolean bCloseConnection)
  859. {
  860. return getXML(oParams, zRowsetName, zRowName, bCloseConnection, null, null, null);
  861. }
  862. public String getXML(DBParams oParams, String zRowsetName, String zRowName, Boolean bCloseConnection, Int32? StartRow, Int32? MaxRows, Boolean? ShowTotal)
  863. {
  864. return getXMLStringBuilder(oParams, zRowsetName, zRowName, bCloseConnection, StartRow, MaxRows, ShowTotal).ToString();
  865. }
  866. public XMLHelper getXMLHelper(DBParams oParams, String zRowsetName, String zRowName, Boolean bCloseConnection, Int32? StartRow, Int32? MaxRows, Boolean? ShowTotal)
  867. {
  868. return new XMLHelper(getXMLStringBuilder(oParams, zRowsetName, zRowName, bCloseConnection, StartRow, MaxRows, ShowTotal));
  869. }
  870. /// <summary>
  871. /// High performance version of append to dom.
  872. /// Will always add columns as attributes.
  873. /// </summary>
  874. private StringBuilder getXMLStringBuilder(DBParams oParams, String zRowsetName, String zRowName, Boolean bCloseConnection, Int32? StartRow, Int32? MaxRows, Boolean? ShowTotal)
  875. {
  876. //Execute the procedure...
  877. //System.Data.IDbCommand oCommand = oParams.AsIDbCommand();
  878. DbCommand oCommand = oParams.Command;
  879. IDataReader oRS = null;
  880. if (bCloseConnection)
  881. {
  882. oRS = oCommand.ExecuteReader(CommandBehavior.CloseConnection);
  883. }
  884. else
  885. {
  886. oRS = oCommand.ExecuteReader();
  887. }
  888. //Get the number of columns...
  889. Int32 FieldCount = oRS.FieldCount;
  890. //Get the column names (in advance of the loop, so it doesn't
  891. //need to read the rowset every time through...
  892. Dictionary<Int32, String> oColumnNames = new Dictionary<Int32, String>();
  893. String ColName = null;
  894. for (int i = 0; i < FieldCount; i++)
  895. {
  896. ColName = oRS.GetName(i).ToLower();
  897. if (ColName.StartsWith("@"))
  898. {
  899. ColName = ColName.Substring(1);
  900. }
  901. oColumnNames.Add(i, ColName);
  902. }
  903. StringWriter sw = new StringWriter();
  904. XmlTextWriter xtw = new XmlTextWriter(sw);
  905. //Append a placeholder for the rows...
  906. xtw.WriteStartElement("response");
  907. if (zRowsetName != null)
  908. xtw.WriteStartElement(zRowsetName);
  909. //Paging setup...
  910. if (StartRow == null) StartRow = 0;
  911. if (MaxRows == null) MaxRows = 0;
  912. if (MaxRows == 0) MaxRows = int.MaxValue;
  913. //Loop through every row in the rs, adding rows and cols appropriately...
  914. Int32 rowCount = 0;
  915. Boolean WriteRow = true;
  916. while (oRS.Read())
  917. {
  918. //If you are at the start row...
  919. if (rowCount >= StartRow && WriteRow)
  920. {
  921. //Add a new row...
  922. xtw.WriteStartElement(zRowName);
  923. for (int i = 0; i < FieldCount; i++)
  924. {
  925. // Add the field to the current row
  926. xtw.WriteAttributeString(oColumnNames[i].ToString(), oRS[i].ToString());
  927. }
  928. xtw.WriteEndElement();
  929. //If you have reached the max number of rows you want to paint, then stop painting...
  930. if ((rowCount - StartRow) >= (MaxRows-1))
  931. WriteRow = false;
  932. }
  933. rowCount++;
  934. }
  935. if (zRowsetName != null)
  936. {
  937. xtw.WriteElementString("total_rows", rowCount.ToString());
  938. xtw.WriteEndElement();
  939. }
  940. xtw.WriteElementString("total_rows", rowCount.ToString());
  941. xtw.WriteEndElement();
  942. //Close the rs...
  943. oRS.Close();
  944. //Return the built dom...
  945. return sw.GetStringBuilder();
  946. }
  947. public StringBuilder getCSV(DBParams oParams, String zRowsetName, String zRowName,
  948. Boolean bCloseConnection, Int32? StartRow, Int32? MaxRows, Boolean? ShowTotal,
  949. out long rowCount)
  950. {
  951. //Execute the procedure...
  952. //System.Data.IDbCommand oCommand = oParams.AsIDbCommand();
  953. DbCommand oCommand = oParams.Command;
  954. DbDataReader oRS = null;
  955. if (bCloseConnection)
  956. {
  957. oRS = oCommand.ExecuteReader(CommandBehavior.CloseConnection);
  958. }
  959. else
  960. {
  961. oRS = oCommand.ExecuteReader();
  962. }
  963. //Get the number of columns...
  964. Int32 FieldCount = oRS.FieldCount;
  965. StringWriter sw = new StringWriter();
  966. //Get the column names (in advance of the loop, so it doesn't
  967. //need to read the rowset every time through...
  968. Dictionary<Int32, String> oColumnNames = new Dictionary<Int32, String>();
  969. String ColName = null;
  970. for (int i = 0; i < FieldCount; i++)
  971. {
  972. ColName = oRS.GetName(i).ToLower();
  973. if (ColName.StartsWith("@"))
  974. {
  975. ColName = ColName.Substring(1);
  976. }
  977. oColumnNames.Add(i, ColName);
  978. sw.Write(ColName);
  979. if (i < (FieldCount - 1))
  980. sw.Write(",");
  981. }
  982. sw.Write(Environment.NewLine);
  983. //Paging setup...
  984. if (StartRow == null) StartRow = 0;
  985. if (MaxRows == null) MaxRows = 0;
  986. if (MaxRows == 0) MaxRows = int.MaxValue;
  987. Type type;
  988. //Loop through every row in the rs, adding rows and cols appropriately...
  989. rowCount = 0;
  990. Boolean WriteRow = true;
  991. while (oRS.Read())
  992. {
  993. //If you are at the start row...
  994. if (rowCount >= StartRow && WriteRow)
  995. {
  996. for (int i = 0; i < FieldCount; i++)
  997. {
  998. type = oRS[i].GetType();
  999. if ((type == typeof(String)))
  1000. sw.Write("\"");
  1001. else if (oColumnNames[i] == "ean_code") //always output ean codes as text to avoid conversion by excel to exponents
  1002. sw.Write("=\"");
  1003. sw.Write(oRS[i].ToString());
  1004. if (type == typeof(String))
  1005. sw.Write("\"");
  1006. else if (oColumnNames[i] == "ean_code") //always output ean codes as text to avoid conversion by excel to exponents
  1007. sw.Write("\"");
  1008. if (i < (FieldCount-1))
  1009. sw.Write(",");
  1010. }
  1011. sw.Write(Environment.NewLine);
  1012. //If you have reached the max number of rows you want to paint, then stop painting...
  1013. if ((rowCount - StartRow) >= (MaxRows - 1))
  1014. WriteRow = false;
  1015. }
  1016. rowCount++;
  1017. }
  1018. //Close the rs...
  1019. oRS.Close();
  1020. //Return the built csv...
  1021. return sw.GetStringBuilder();
  1022. }
  1023. #endregion
  1024. }
  1025. }