PageRenderTime 38ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/EffiProz-CF/Core/TextTable.cs

#
C# | 438 lines | 258 code | 90 blank | 90 comment | 41 complexity | 23926fad1cc6a0c71dcc065a1d0fa613 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. //
  2. // (C) Copyright 2009 Irantha Suwandarathna (irantha@gmail.com)
  3. // All rights reserved.
  4. //
  5. /* Copyright (c) 2001-2008, The HSQL Development Group
  6. * All rights reserved.
  7. *
  8. * Redistribution and use _in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions are met:
  10. *
  11. * Redistributions of source code must retain the above copyright notice, this
  12. * list of conditions and the following disclaimer.
  13. *
  14. * Redistributions _in binary form must reproduce the above copyright notice,
  15. * this list of conditions and the following disclaimer _in the documentation
  16. * and/or other materials provided with the distribution.
  17. *
  18. * Neither the name of the HSQL Development Group nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
  26. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  27. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  28. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  30. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. using System;
  35. using System.Collections.Generic;
  36. using System.Text;
  37. using System.Linq;
  38. using System.Reflection;
  39. using System.IO;
  40. using EffiProz.Core.Lib;
  41. using EffiProz.Core.ScriptIO;
  42. using EffiProz.Core.Persist;
  43. using EffiProz.Core.Errors;
  44. namespace EffiProz.Core
  45. {
  46. // tony_lai@users 20020820 - patch 595099 - user define PK name
  47. /**
  48. * Subclass of Table to handle TEXT data source. <p>
  49. *
  50. *:Table to provide the notion of an SQL base table object whose
  51. * data is read from and written to a text format data file.
  52. *
  53. * @author sqlbob@users (RMP)
  54. * @version 1.8.0
  55. */
  56. public class TextTable : Table
  57. {
  58. private String dataSource = "";
  59. private bool isReversed = false;
  60. private bool _isConnected = false;
  61. // TextCache cache;
  62. /**
  63. * Constructs a new TextTable from the given arguments.
  64. *
  65. * @param db the owning database
  66. * @param name the table's HsqlName
  67. * @param type code (normal or temp text table)
  68. */
  69. public TextTable(Database db, QNameManager.QName name, int type)
  70. : base(db, name, type)
  71. {
  72. }
  73. public bool isConnected()
  74. {
  75. return _isConnected;
  76. }
  77. /**
  78. * connects to the data source
  79. */
  80. public void connect(Session session)
  81. {
  82. connect(session, _isReadOnly);
  83. }
  84. /**
  85. * connects to the data source
  86. */
  87. private void connect(Session session, bool withReadOnlyData)
  88. {
  89. // Open new cache:
  90. if ((dataSource.Length == 0) || _isConnected)
  91. {
  92. // nothing to do
  93. return;
  94. }
  95. PersistentStore store =
  96. database.persistentStoreCollection.getStore(this);
  97. this.store = store;
  98. DataFileCache cache = null;
  99. try
  100. {
  101. cache = (TextCache)database.logger.openTextFilePersistence(this,
  102. dataSource, withReadOnlyData, isReversed);
  103. store.setCache(cache);
  104. // read and insert all the rows from the source file
  105. Row row = null;
  106. int nextpos = 0;
  107. if (((TextCache)cache).ignoreFirst)
  108. {
  109. nextpos += ((TextCache)cache).readHeaderLine();
  110. }
  111. while (true)
  112. {
  113. row = (Row)store.get(nextpos, false);
  114. if (row == null)
  115. {
  116. break;
  117. }
  118. Object[] data = row.getData();
  119. nextpos = row.getPos() + row.getStorageSize();
  120. ((RowAVLDiskData)row).setNewNodes();
  121. systemUpdateIdentityValue(data);
  122. enforceRowConstraints(session, data);
  123. for (int i = 0; i < indexList.Length; i++)
  124. {
  125. indexList[i].insert(null, store, row);
  126. }
  127. }
  128. }
  129. catch (Exception t)
  130. {
  131. int linenumber = cache == null ? 0
  132. : ((TextCache)cache)
  133. .getLineNumber();
  134. clearAllData(session);
  135. if (cache != null)
  136. {
  137. database.logger.closeTextCache(this);
  138. store.release();
  139. }
  140. // everything is in order here.
  141. // At this point table should either have a valid (old) data
  142. // source and cache or have an empty source and null cache.
  143. throw Error.error(t, ErrorCode.TEXT_FILE, 0, new Object[] {
  144. t.Message, linenumber
  145. });
  146. }
  147. _isConnected = true;
  148. _isReadOnly = withReadOnlyData;
  149. }
  150. /**
  151. * disconnects from the data source
  152. */
  153. public void disconnect()
  154. {
  155. this.store = null;
  156. PersistentStore store =
  157. database.persistentStoreCollection.getStore(this);
  158. store.release();
  159. _isConnected = false;
  160. }
  161. /**
  162. * This method does some of the work involved with managing the creation
  163. * and openning of the cache, the rest is done in Log.java and
  164. * TextCache.java.
  165. *
  166. * Better clarification of the role of the methods is needed.
  167. */
  168. private void openCache(Session session, String dataSourceNew,
  169. bool isReversedNew, bool isReadOnlyNew)
  170. {
  171. String dataSourceOld = dataSource;
  172. bool isReversedOld = isReversed;
  173. bool isReadOnlyOld = _isReadOnly;
  174. if (dataSourceNew == null)
  175. {
  176. dataSourceNew = "";
  177. }
  178. disconnect();
  179. dataSource = dataSourceNew;
  180. isReversed = (isReversedNew && dataSource.Length > 0);
  181. try
  182. {
  183. connect(session, isReadOnlyNew);
  184. }
  185. catch (CoreException e)
  186. {
  187. dataSource = dataSourceOld;
  188. isReversed = isReversedOld;
  189. connect(session, isReadOnlyOld);
  190. throw e;
  191. }
  192. }
  193. /**
  194. * High level command to assign a data source to the table definition.
  195. * Reassigns only if the data source or direction has changed.
  196. */
  197. public void setDataSource(Session session, String dataSourceNew,
  198. bool isReversedNew, bool createFile)
  199. {
  200. if (getTableType() == Table.TEMP_TEXT_TABLE)
  201. {
  202. ;
  203. }
  204. else
  205. {
  206. session.getGrantee().checkSchemaUpdateOrGrantRights(
  207. getSchemaName().name);
  208. }
  209. dataSourceNew = dataSourceNew.Trim();
  210. if (createFile && FileUtil.GetDefaultInstance().exists(dataSourceNew))
  211. {
  212. throw Error.error(ErrorCode.TEXT_SOURCE_EXISTS, dataSourceNew);
  213. }
  214. //-- Open if descending, direction changed, file changed, or not connected currently
  215. if (isReversedNew || (isReversedNew != isReversed)
  216. || !dataSource.Equals(dataSourceNew) || !_isConnected)
  217. {
  218. openCache(session, dataSourceNew, isReversedNew, _isReadOnly);
  219. }
  220. if (isReversed)
  221. {
  222. _isReadOnly = true;
  223. }
  224. }
  225. public String getDataSource()
  226. {
  227. return dataSource;
  228. }
  229. public bool isDescDataSource()
  230. {
  231. return isReversed;
  232. }
  233. public void setHeader(String header)
  234. {
  235. PersistentStore store =
  236. database.persistentStoreCollection.getStore(this);
  237. TextCache cache = (TextCache)store.getCache();
  238. if (cache != null && cache.ignoreFirst)
  239. {
  240. cache.setHeader(header);
  241. return;
  242. }
  243. throw Error.error(ErrorCode.TEXT_TABLE_HEADER);
  244. }
  245. public String getHeader()
  246. {
  247. PersistentStore store =
  248. database.persistentStoreCollection.getStore(this);
  249. TextCache cache = (TextCache)store.getCache();
  250. String header = cache == null ? null
  251. : cache.getHeader();
  252. return header == null ? null
  253. : StringConverter.toQuotedString(header, '\'',
  254. true);
  255. }
  256. /**
  257. * Used by INSERT, DELETE, UPDATE operations. This class will return
  258. * a more appropriate message when there is no data source.
  259. */
  260. public override void checkDataReadOnly()
  261. {
  262. if (dataSource.Length == 0)
  263. {
  264. throw Error.error(ErrorCode.TEXT_TABLE_UNKNOWN_DATA_SOURCE);
  265. }
  266. if (_isReadOnly)
  267. {
  268. throw Error.error(ErrorCode.DATA_IS_READONLY);
  269. }
  270. }
  271. public override bool isDataReadOnly()
  272. {
  273. return !isConnected() || base.isDataReadOnly() ||
  274. store.getCache().isDataReadOnly();
  275. }
  276. public override void setDataReadOnly(bool value)
  277. {
  278. if (!value)
  279. {
  280. if (isReversed)
  281. {
  282. throw Error.error(ErrorCode.DATA_IS_READONLY);
  283. }
  284. if (database.isFilesReadOnly())
  285. {
  286. throw Error.error(ErrorCode.DATABASE_IS_READONLY);
  287. }
  288. }
  289. _isReadOnly = value;
  290. }
  291. public override bool isIndexCached()
  292. {
  293. return false;
  294. }
  295. public void setIndexRoots(String s)
  296. {
  297. // do nothing
  298. }
  299. public String getDataSourceDDL()
  300. {
  301. String dataSource = getDataSource();
  302. if (dataSource == null)
  303. {
  304. return null;
  305. }
  306. bool isDesc = isDescDataSource();
  307. StringBuilder sb = new StringBuilder(128);
  308. sb.Append(Tokens.T_SET).Append(' ').Append(Tokens.T_TABLE).Append(' ');
  309. sb.Append(getName().getSchemaQualifiedStatementName());
  310. sb.Append(' ').Append(Tokens.T_SOURCE).Append(' ').Append('\'');
  311. sb.Append(dataSource);
  312. sb.Append('\'');
  313. if (isDesc)
  314. {
  315. sb.Append(' ').Append(Tokens.T_DESC);
  316. }
  317. return sb.ToString();
  318. }
  319. /**
  320. * Generates the SET TABLE <tablename> SOURCE HEADER <string> statement for a
  321. * text table;
  322. */
  323. public String getDataSourceHeader()
  324. {
  325. String header = getHeader();
  326. if (header == null)
  327. {
  328. return null;
  329. }
  330. StringBuilder sb = new StringBuilder(128);
  331. sb.Append(Tokens.T_SET).Append(' ').Append(Tokens.T_TABLE).Append(' ');
  332. sb.Append(getName().getSchemaQualifiedStatementName());
  333. sb.Append(' ').Append(Tokens.T_SOURCE).Append(' ');
  334. sb.Append(Tokens.T_HEADER).Append(' ');
  335. sb.Append(header);
  336. return sb.ToString();
  337. }
  338. /**
  339. * Adds commitPersistence() call
  340. */
  341. public override void insertData(PersistentStore store, Object[] data)
  342. {
  343. Row row = (Row)store.getNewCachedObject(null, data);
  344. store.indexRow(null, row);
  345. store.commitPersistence(row);
  346. }
  347. }
  348. }