AbstractDBConnection.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. //
  2. // System.Data.Common.AbstractDBConnection
  3. //
  4. // Authors:
  5. // Konstantin Triger <[email protected]>
  6. // Boris Kirzner <[email protected]>
  7. //
  8. // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
  9. //
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System.Globalization;
  31. using System.Data;
  32. using System.Data.ProviderBase;
  33. using System.Data.Configuration;
  34. using System.Configuration;
  35. using System.Collections;
  36. using System.Collections.Specialized;
  37. using System.Text;
  38. using System.Text.RegularExpressions;
  39. using Mainsoft.Data.Jdbc.Providers;
  40. using System.Data.Common;
  41. using java.sql;
  42. using javax.sql;
  43. using javax.naming;
  44. using Mainsoft.Data.Configuration;
  45. namespace System.Data.ProviderBase
  46. {
  47. public abstract class AbstractDBConnection : DbConnection, ICloneable
  48. {
  49. #region ObjectNamesHelper
  50. private sealed class ObjectNamesHelper
  51. {
  52. //static readonly Regex NameOrder = new Regex(@"^\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  53. static readonly Regex NameOrder = new Regex(@"^((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  54. //static readonly Regex SchemaNameOrder = new Regex(@"^\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  55. static readonly Regex SchemaNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  56. //static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  57. //static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  58. static readonly Regex CatalogSchemaNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  59. //static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  60. //static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  61. static readonly Regex CatalogNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  62. //static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  63. //static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  64. static readonly Regex SchemaCatalogNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
  65. internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)
  66. {
  67. ArrayList collection = new ArrayList();
  68. collection.Add(new ObjectNameResolver(NameOrder));
  69. ObjectNameResolversCollection basic = (ObjectNameResolversCollection) ConfigurationSettings.GetConfig ("Mainsoft.Data.Configuration/objectnameresolution");
  70. java.sql.DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();
  71. string productName = metaData.getDatabaseProductName();
  72. foreach(ObjectNameResolver nameResolver in basic) {
  73. if (productName.IndexOf(nameResolver.DbName) != -1) {
  74. collection.Add(nameResolver);
  75. }
  76. }
  77. //defaults
  78. if (metaData.isCatalogAtStart()) {
  79. collection.Add(new ObjectNameResolver(SchemaNameOrder));
  80. collection.Add(new ObjectNameResolver(CatalogNameOrder));
  81. collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
  82. collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
  83. }
  84. else {
  85. collection.Add(new ObjectNameResolver(CatalogNameOrder));
  86. collection.Add(new ObjectNameResolver(SchemaNameOrder));
  87. collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
  88. collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
  89. }
  90. return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));
  91. }
  92. }
  93. #endregion // ObjectNamesHelper
  94. #region Fields
  95. private const int DEFAULT_TIMEOUT = 15;
  96. private java.sql.Connection _jdbcConnnection;
  97. private ConnectionState _internalState;
  98. private object _internalStateSync = new object();
  99. private string _connectionString = String.Empty;
  100. IConnectionStringDictionary _connectionStringBuilder;
  101. IConnectionProvider _connectionProvider;
  102. private ArrayList _referencedObjects = new ArrayList();
  103. private ObjectNameResolver[] _syntaxPatterns;
  104. #endregion // Fields
  105. #region Constructors
  106. public AbstractDBConnection(string connectionString)
  107. {
  108. _connectionString = connectionString;
  109. }
  110. #endregion // Constructors
  111. #region Properties
  112. public override String ConnectionString
  113. {
  114. get { return _connectionString; }
  115. set {
  116. if (IsOpened) {
  117. throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);
  118. }
  119. _connectionString = value;
  120. _connectionProvider = null;
  121. _connectionStringBuilder = null;
  122. }
  123. }
  124. public override int ConnectionTimeout
  125. {
  126. get {
  127. string timeoutStr = (string)ConnectionStringBuilder["loginTimeout"];
  128. if (timeoutStr != null && timeoutStr.Length > 0) {
  129. try {
  130. return Convert.ToInt32(timeoutStr);
  131. }
  132. catch(FormatException) {
  133. throw ExceptionHelper.InvalidValueForKey("connect timeout");
  134. }
  135. catch (OverflowException) {
  136. throw ExceptionHelper.InvalidValueForKey("connect timeout");
  137. }
  138. }
  139. return DEFAULT_TIMEOUT;
  140. }
  141. }
  142. public override String Database
  143. {
  144. get {
  145. if ((State & ConnectionState.Open) != 0)
  146. return JdbcConnection.getCatalog();
  147. return (string)ConnectionStringBuilder["DATABASE"];
  148. }
  149. }
  150. public override ConnectionState State
  151. {
  152. get {
  153. try {
  154. if ((JdbcConnection == null) || JdbcConnection.isClosed()) {
  155. // jdbc connection not initialized or closed
  156. if (_internalState == ConnectionState.Closed ) {
  157. return ConnectionState.Closed;
  158. }
  159. }
  160. else {
  161. // jdbc connection is opened
  162. if ((_internalState & ConnectionState.Open) != 0) {
  163. return ConnectionState.Open;
  164. }
  165. }
  166. return ConnectionState.Broken;
  167. }
  168. catch (SQLException) {
  169. return ConnectionState.Broken;
  170. }
  171. }
  172. }
  173. internal bool IsExecuting
  174. {
  175. get {
  176. return ((_internalState & ConnectionState.Executing) != 0);
  177. }
  178. set {
  179. lock(_internalStateSync) {
  180. // to switch to executing, the connection must be in opened
  181. if (value) {
  182. if (_internalState != ConnectionState.Open) {
  183. if (IsFetching) {
  184. throw ExceptionHelper.OpenedReaderExists();
  185. }
  186. throw ExceptionHelper.OpenConnectionRequired("",_internalState);
  187. }
  188. _internalState |= ConnectionState.Executing;
  189. }
  190. else {
  191. if (!IsExecuting) {
  192. throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Executing.ToString() + " while in state " + _internalState.ToString());
  193. }
  194. _internalState &= ~ConnectionState.Executing;
  195. }
  196. }
  197. }
  198. }
  199. internal bool IsFetching
  200. {
  201. get {
  202. return ((_internalState & ConnectionState.Fetching) != 0);
  203. }
  204. set {
  205. lock(_internalStateSync) {
  206. if (value) {
  207. // to switch to fetching connection must be in opened, executing
  208. if (((_internalState & ConnectionState.Open) == 0) || ((_internalState & ConnectionState.Executing) == 0)) {
  209. throw ExceptionHelper.OpenConnectionRequired("",_internalState);
  210. }
  211. _internalState |= ConnectionState.Fetching;
  212. }
  213. else {
  214. if (!IsFetching) {
  215. throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());
  216. }
  217. _internalState &= ~ConnectionState.Fetching;
  218. }
  219. }
  220. }
  221. }
  222. internal bool IsOpened
  223. {
  224. get {
  225. return ((_internalState & ConnectionState.Open) != 0);
  226. }
  227. set {
  228. lock(_internalStateSync) {
  229. if (value) {
  230. // only connecting connection can be opened
  231. if ((_internalState != ConnectionState.Connecting)) {
  232. throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
  233. }
  234. _internalState |= ConnectionState.Open;
  235. }
  236. else {
  237. if (!IsOpened) {
  238. throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());
  239. }
  240. _internalState &= ~ConnectionState.Open;
  241. }
  242. }
  243. }
  244. }
  245. internal bool IsConnecting
  246. {
  247. get {
  248. return ((_internalState & ConnectionState.Connecting) != 0);
  249. }
  250. set {
  251. lock(_internalStateSync) {
  252. if (value) {
  253. // to switch to connecting conection must be in closed or in opened
  254. if ((_internalState != ConnectionState.Closed) && (_internalState != ConnectionState.Open)) {
  255. throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
  256. }
  257. _internalState |= ConnectionState.Connecting;
  258. }
  259. else {
  260. if (!IsConnecting) {
  261. throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Connecting.ToString() + " while in state " + _internalState.ToString());
  262. }
  263. _internalState &= ~ConnectionState.Connecting;
  264. }
  265. }
  266. }
  267. }
  268. public override string DataSource
  269. {
  270. get {
  271. return (string)ConnectionStringBuilder["SERVERNAME"];
  272. }
  273. }
  274. internal ConnectionState InternalState
  275. {
  276. get { return _internalState; }
  277. }
  278. protected internal java.sql.Connection JdbcConnection
  279. {
  280. get { return _jdbcConnnection; }
  281. set { _jdbcConnnection = value; }
  282. }
  283. internal ObjectNameResolver[] SyntaxPatterns
  284. {
  285. get {
  286. if (_syntaxPatterns == null) {
  287. _syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);
  288. }
  289. return _syntaxPatterns;
  290. }
  291. }
  292. protected internal IConnectionProvider ConnectionProvider {
  293. get {
  294. try {
  295. if (_connectionProvider == null)
  296. _connectionProvider = GetConnectionProvider();
  297. return _connectionProvider;
  298. }
  299. catch(SQLException exp) {
  300. throw CreateException(exp);
  301. }
  302. }
  303. }
  304. protected internal IConnectionStringDictionary ConnectionStringBuilder {
  305. get {
  306. try {
  307. if (_connectionStringBuilder == null)
  308. _connectionStringBuilder = ConnectionProvider.GetConnectionStringBuilder(ConnectionString);
  309. return _connectionStringBuilder;
  310. }
  311. catch(SQLException exp) {
  312. throw CreateException(exp);
  313. }
  314. }
  315. }
  316. protected abstract IConnectionProvider GetConnectionProvider();
  317. static protected IConnectionProvider GetConnectionProvider(string sectionMame, string provider) {
  318. if (provider == null)
  319. throw new ArgumentNullException("provider");
  320. IList providers = (IList) ConfigurationSettings.GetConfig(sectionMame);
  321. if (providers.Count == 0)
  322. throw new ArgumentException("Configuration section is empty.", "sectionName");
  323. for (int i = 0; i < providers.Count; i++) {
  324. IDictionary providerInfo = (IDictionary) providers[i];
  325. string curProvider = (string)providerInfo[ConfigurationConsts.Name];
  326. if (String.Compare(provider, 0, curProvider, 0, provider.Length, true, CultureInfo.InvariantCulture) == 0) {
  327. string providerType = (string) providerInfo [ConfigurationConsts.ProviderType];
  328. if (providerType == null || providerType.Length == 0)
  329. return new GenericProvider (providerInfo);
  330. else {
  331. Type t = Type.GetType (providerType);
  332. return (IConnectionProvider) Activator.CreateInstance (t , new object[] {providerInfo});
  333. }
  334. }
  335. }
  336. throw new ArgumentException(
  337. String.Format("Unknown provider name '{0}'", provider), "ConnectionString");
  338. }
  339. #endregion // Properties
  340. #region Methods
  341. // since WS also does not permits dynamically change of login timeout and tomcat does no implements - do not do it at all
  342. //ds.setLoginTimeout(ConnectionTimeout);
  343. protected internal abstract void OnSqlWarning(SQLWarning warning);
  344. protected abstract SystemException CreateException(SQLException e);
  345. protected abstract SystemException CreateException(string message);
  346. public override void Close()
  347. {
  348. ConnectionState orig = State;
  349. try {
  350. ClearReferences();
  351. if (JdbcConnection != null && !JdbcConnection.isClosed()) {
  352. if (!JdbcConnection.getAutoCommit())
  353. JdbcConnection.rollback();
  354. JdbcConnection.close();
  355. }
  356. }
  357. catch (Exception e) {
  358. // suppress exception
  359. #if DEBUG
  360. Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
  361. #endif
  362. }
  363. finally {
  364. JdbcConnection = null;
  365. lock(_internalStateSync) {
  366. _internalState = ConnectionState.Closed;
  367. }
  368. }
  369. ConnectionState current = State;
  370. if (current != orig)
  371. OnStateChange (new StateChangeEventArgs (orig, current));
  372. }
  373. internal protected virtual void OnSqlException(SQLException exp)
  374. {
  375. throw CreateException(exp);
  376. }
  377. internal void AddReference(object referencedObject)
  378. { lock(_referencedObjects.SyncRoot) {
  379. _referencedObjects.Add(new WeakReference(referencedObject));
  380. }
  381. }
  382. internal void RemoveReference(object referencedObject)
  383. {
  384. lock(_referencedObjects.SyncRoot) {
  385. for(int i = 0; i < _referencedObjects.Count; i++) {
  386. WeakReference wr = (WeakReference) _referencedObjects[i];
  387. if (wr.IsAlive && (wr.Target == referencedObject)) {
  388. _referencedObjects.RemoveAt(i);
  389. }
  390. }
  391. }
  392. }
  393. private void ClearReferences()
  394. {
  395. ArrayList oldList = _referencedObjects;
  396. _referencedObjects = new ArrayList();
  397. for(int i = 0; i < oldList.Count; i++) {
  398. WeakReference wr = (WeakReference) oldList[i];
  399. if (wr.IsAlive) {
  400. ClearReference(wr.Target);
  401. }
  402. }
  403. }
  404. private void ClearReference(object referencedObject)
  405. {
  406. try {
  407. if (referencedObject is AbstractDbCommand) {
  408. ((AbstractDbCommand)referencedObject).CloseInternal();
  409. }
  410. else if (referencedObject is AbstractDataReader) {
  411. ((AbstractDataReader)referencedObject).CloseInternal();
  412. }
  413. }
  414. catch (SQLException) {
  415. // suppress exception since it's possible that command or reader are in inconsistent state
  416. }
  417. }
  418. public override void Open()
  419. {
  420. if (_connectionString == null || _connectionString.Length == 0) {
  421. throw ExceptionHelper.ConnectionStringNotInitialized();
  422. }
  423. IsConnecting = true;
  424. try {
  425. if (JdbcConnection != null && !JdbcConnection.isClosed()) {
  426. throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
  427. }
  428. JdbcConnection = ConnectionProvider.GetConnection (ConnectionStringBuilder);
  429. IsOpened = true;
  430. OnStateChange (new StateChangeEventArgs (ConnectionState.Closed, ConnectionState.Open));
  431. }
  432. catch (SQLWarning warning) {
  433. OnSqlWarning(warning);
  434. }
  435. catch (SQLException exp) {
  436. OnSqlException(exp);
  437. }
  438. finally {
  439. IsConnecting = false;
  440. }
  441. }
  442. public override void ChangeDatabase(String database)
  443. {
  444. IsConnecting = true;
  445. try {
  446. ClearReferences();
  447. java.sql.Connection con = JdbcConnection;
  448. con.setCatalog(database);
  449. // ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);
  450. }
  451. catch (SQLWarning warning) {
  452. OnSqlWarning(warning);
  453. }
  454. catch (SQLException exp) {
  455. throw CreateException(exp);
  456. }
  457. finally {
  458. IsConnecting = false;
  459. }
  460. }
  461. public override string ServerVersion {
  462. get {
  463. // only if the driver support this methods
  464. try {
  465. if (JdbcConnection == null)
  466. return String.Empty;
  467. java.sql.DatabaseMetaData metaData = JdbcConnection.getMetaData();
  468. return metaData.getDatabaseProductVersion();
  469. }
  470. catch (SQLException exp) {
  471. throw CreateException(exp);
  472. }
  473. }
  474. }
  475. internal string JdbcProvider {
  476. get {
  477. // only if the driver support this methods
  478. try {
  479. if (JdbcConnection == null)
  480. return String.Empty;
  481. java.sql.DatabaseMetaData metaData = JdbcConnection.getMetaData();
  482. return metaData.getDriverName() + " " + metaData.getDriverVersion();
  483. }
  484. catch (SQLException exp) {
  485. return String.Empty; //suppress
  486. }
  487. }
  488. }
  489. protected override void Dispose(bool disposing)
  490. {
  491. if (disposing) {
  492. try {
  493. if (JdbcConnection != null && !JdbcConnection.isClosed()) {
  494. JdbcConnection.close();
  495. }
  496. JdbcConnection = null;
  497. }
  498. catch (java.sql.SQLException exp) {
  499. throw CreateException(exp);
  500. }
  501. }
  502. base.Dispose(disposing);
  503. }
  504. internal void ValidateBeginTransaction()
  505. {
  506. if (State != ConnectionState.Open) {
  507. throw new InvalidOperationException(String.Format("{0} requires an open and available Connection. The connection's current state is {1}.", new object[] {"BeginTransaction", State}));
  508. }
  509. if (!JdbcConnection.getAutoCommit()) {
  510. throw new System.InvalidOperationException("Parallel transactions are not supported.");
  511. }
  512. }
  513. internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)
  514. {
  515. ArrayList col = new ArrayList();
  516. try {
  517. ObjectNameResolver[] nameResolvers = SyntaxPatterns;
  518. java.sql.ResultSet res = null;
  519. string catalog = null;
  520. string schema = null;
  521. string spname = null;
  522. java.sql.DatabaseMetaData metadata = JdbcConnection.getMetaData();
  523. bool storesUpperCaseIdentifiers = false;
  524. bool storesLowerCaseIdentifiers = false;
  525. try {
  526. storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();
  527. storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();
  528. }
  529. catch (SQLException e) {
  530. // suppress
  531. }
  532. for(int i=0; i < nameResolvers.Length; i++) {
  533. ObjectNameResolver nameResolver = nameResolvers[i];
  534. Match match = nameResolver.Match(procedureString);
  535. if (match.Success) {
  536. spname = ObjectNameResolver.GetName(match);
  537. schema = ObjectNameResolver.GetSchema(match);
  538. catalog = ObjectNameResolver.GetCatalog(match);
  539. // make all identifiers uppercase or lowercase according to database metadata
  540. if (storesUpperCaseIdentifiers) {
  541. spname = (spname.Length > 0) ? spname.ToUpper() : null;
  542. schema = (schema.Length > 0) ? schema.ToUpper() : null;
  543. catalog = (catalog.Length > 0) ? catalog.ToUpper() : null;
  544. }
  545. else if (storesLowerCaseIdentifiers) {
  546. spname = (spname.Length > 0) ? spname.ToLower() : null;
  547. schema = (schema.Length > 0) ? schema.ToLower() : null;
  548. catalog = (catalog.Length > 0) ? catalog.ToLower() : null;
  549. }
  550. else {
  551. spname = (spname.Length > 0) ? spname : null;
  552. schema = (schema.Length > 0) ? schema : null;
  553. catalog = (catalog.Length > 0) ? catalog : null;
  554. }
  555. // catalog from db is always in correct caps
  556. if (catalog == null) {
  557. catalog = JdbcConnection.getCatalog();
  558. }
  559. try {
  560. // always get the first procedure that db returns
  561. res = metadata.getProcedures(catalog, schema, spname);
  562. if (res.next()) {
  563. catalog = res.getString(1);
  564. schema = res.getString(2);
  565. spname = res.getString(3);
  566. break;
  567. }
  568. spname = null;
  569. }
  570. catch { // suppress exception
  571. return null;
  572. }
  573. finally {
  574. if (res != null) {
  575. res.close();
  576. }
  577. }
  578. }
  579. }
  580. if (spname == null || spname.Length == 0) {
  581. return null;
  582. }
  583. try {
  584. // get procedure columns based o procedure metadata
  585. res = metadata.getProcedureColumns(catalog, schema, spname, null);
  586. while (res.next()) {
  587. // since there is still a possibility that some of the parameters to getProcedureColumn were nulls,
  588. // we need to filter the results with strict matching
  589. if ((res.getString(1) != catalog ) || (res.getString(2) != schema) || (res.getString(3) != spname)) {
  590. continue;
  591. }
  592. AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();
  593. parameter.SetParameterName(res);
  594. parameter.SetParameterDbType(res);
  595. parameter.SetSpecialFeatures(res);
  596. //get parameter direction
  597. short direction = res.getShort("COLUMN_TYPE");
  598. if(direction == 1) //DatabaseMetaData.procedureColumnIn
  599. parameter.Direction = ParameterDirection.Input;
  600. else if(direction == 2) //DatabaseMetaData.procedureColumnInOut
  601. parameter.Direction = ParameterDirection.InputOutput;
  602. else if(direction == 4) //DatabaseMetaData.procedureColumnOut
  603. parameter.Direction = ParameterDirection.Output;
  604. else if(direction == 5) //DatabaseMetaData.procedureColumnReturn
  605. parameter.Direction = ParameterDirection.ReturnValue;
  606. //get parameter precision and scale
  607. parameter.SetParameterPrecisionAndScale(res);
  608. parameter.SetParameterSize(res);
  609. parameter.SetParameterIsNullable(res);
  610. col.Add(parameter);
  611. }
  612. }
  613. finally {
  614. if (res != null) {
  615. res.close();
  616. }
  617. }
  618. }
  619. catch(Exception e) {
  620. //supress
  621. #if DEBUG
  622. Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
  623. #endif
  624. }
  625. return col;
  626. }
  627. #endregion // Methods
  628. #region ICloneable Members
  629. public virtual object Clone() {
  630. AbstractDBConnection con = (AbstractDBConnection)MemberwiseClone();
  631. con._internalState = ConnectionState.Closed;
  632. con._internalStateSync = new object();
  633. con._jdbcConnnection = null;
  634. con._referencedObjects = new ArrayList();
  635. con._syntaxPatterns = null;
  636. return con;
  637. }
  638. #endregion
  639. }
  640. }