GetBytes should return the data length if target buffer is null
[mono.git] / mcs / class / System.Data / System.Data.ProviderBase.jvm / AbstractDBCommand.cs
1 //\r
2 // System.Data.ProviderBase.AbstractDbCommand\r
3 //
4 // Authors:
5 //      Konstantin Triger <kostat@mainsoft.com>
6 //      Boris Kirzner <borisk@mainsoft.com>
7 //      
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //\r
31 \r
32 \r
33 using System;\r
34 using System.Text;\r
35 using System.Text.RegularExpressions;\r
36 using System.Collections;\r
37 using System.Data;\r
38 using System.Data.Common;\r
39 \r
40 using java.sql;\r
41 using java.io;\r
42 \r
43 #if !USE_DOTNET_REGEXP\r
44 using java.util.regex;\r
45 #endif\r
46 \r
47 namespace System.Data.ProviderBase\r
48 {\r
49         public abstract class AbstractDbCommand : DbCommandBase\r
50         {\r
51                 #region ProcedureColumnCache
52
53                 internal sealed class ProcedureColumnCache : AbstractDbMetaDataCache\r
54                 {\r
55                         internal ArrayList GetProcedureColumns(AbstractDBConnection connection, String commandText,AbstractDbCommand command) \r
56                         {\r
57                                 string connectionCatalog = connection.JdbcConnection.getCatalog();\r
58                                 string key = String.Concat(connection.ConnectionString, connectionCatalog, commandText);\r
59                                 System.Collections.Hashtable cache = Cache;\r
60 \r
61                                 ArrayList col = cache[key] as ArrayList;\r
62 \r
63                                 if (null != col) {\r
64                                         return col;\r
65                                 }\r
66         \r
67                                 col = connection.GetProcedureColumns(commandText,command);\r
68                                 if (col != null)\r
69                                         cache[key] = col;\r
70                                 return col;                             \r
71                         }\r
72                 }
73
74                 #endregion
75
76                 #region SqlStatementsHelper
77
78                 internal sealed class SqlStatementsHelper
79                 {
80                         #region Fields
81 #if USE_DOTNET_REGEXP                   \r
82                         internal static readonly Regex NamedParameterStoredProcedureRegExp = new Regex(@"^\s*{?\s*((?<RETVAL>@\w+)\s*=\s*)?call\s+(?<PROCNAME>(((\[[^\]]*\])|([^\.\(])*)\s*\.\s*){0,2}(\[[^\]]*\]|((\s*[^\.\(\)\{\}\s])+)))\s*(\(\s*(?<USERPARAM>((""([^""]|(""""))*"")|('([^']|(''))*')|[^,])*)?\s*(,\s*(?<USERPARAM>((""([^""]|(""""))*"")|('([^']|(''))*')|[^,])*)\s*)*\))?\s*}?\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
83                         internal static readonly Regex SimpleParameterStoredProcedureRegExp = new Regex(@"^\s*{?\s*((?<RETVAL>\?)\s*=\s*)?call\s+(?<PROCNAME>(((\[[^\]]*\])|([^\.\(])*)\s*\.\s*){0,2}(\[[^\]]*\]|((\s*[^\.\(\)\{\}\s])+)))\s*(\(\s*(?<USERPARAM>((""([^""]|(""""))*"")|('([^']|(''))*')|[^,])*)?\s*(,\s*(?<USERPARAM>((""([^""]|(""""))*"")|('([^']|(''))*')|[^,])*)\s*)*\))?\s*}?\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
84 #else\r
85                         internal static readonly Pattern NamedParameterStoredProcedureRegExp = Pattern.compile(@"^\s*\{?\s*(?:(@\w+)\s*=\s*)?call\s+((?:(?:(?:\[[^\]]*\])|(?:[^\.\(\)\{\}\[\]])*)\s*\.\s*){0,2}(?:\[[^\]]*\]|(?:(?:\s*[^\.\(\)\{\}\[\]])+)))\s*(?:\((.*)\))?\s*\}?\s*$", Pattern.CASE_INSENSITIVE);\r
86                         internal static readonly Pattern SimpleParameterStoredProcedureRegExp = Pattern.compile(@"^\s*\{?\s*(?:(\?)\s*=\s*)?call\s+((?:(?:(?:\[[^\]]*\])|(?:[^\.\(\)\{\}\[\]])*)\s*\.\s*){0,2}(?:\[[^\]]*\]|(?:(?:\s*[^\.\(\)\{\}\[\]])+)))\s*(?:\((.*)\))?\s*\}?\s*$", Pattern.CASE_INSENSITIVE);\r
87 #endif\r
88 \r
89 //                      internal static readonly Regex NamedParameterRegExp = new Regex(@"((?<USERPARAM>@\w+)|(\[[^\[\]]*\])|(""([^""]|(""""))*"")|('([^']|(''))*'))*", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
90 //                      internal static readonly Regex SimpleParameterRegExp = new Regex(@"((?<USERPARAM>\?)|(\[[^\[\]]*\])|(""([^""]|(""""))*"")|('([^']|(''))*'))*", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
91                         internal static readonly SimpleRegex NamedParameterRegExp = new SqlParamsRegex();\r
92                         internal static readonly SimpleRegex SimpleParameterRegExp = new OleDbParamsRegex();\r
93 \r
94                         internal static readonly Regex SelectFromStatementReqExp = new Regex(@"^\s*SELECT\s+(((\[[^\[\]]*\])|(""([^""]|(""""))*"")|('([^']|(''))*')|[^'""\[])*\s+)*FROM\s+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
95                         internal static readonly Regex ForBrowseStatementReqExp = new Regex(@"\s+FOR\s+BROWSE\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
96 \r
97                         internal static readonly SimpleRegex CompoundStatementSplitterReqExp = new CharacterSplitterRegex(';');\r
98                         internal static readonly SimpleRegex ProcedureParameterSplitterReqExp = new CharacterSplitterRegex(',');\r
99 \r
100                         #endregion // Fields
101                 }
102
103                 #endregion // SqlStatementsHelper
104 \r
105                 #region Fields\r
106 \r
107                 protected DbParameterCollection _parameters;\r
108                 protected java.sql.Statement _statement;\r
109                 protected AbstractDBConnection _connection;\r
110                 protected AbstractTransaction _transaction;\r
111                 private bool _isCommandPrepared;\r
112                 protected CommandBehavior _behavior;\r
113                 private ArrayList _internalParameters;\r
114                 string _javaCommandText;\r
115                 private int _recordsAffected;\r
116                 private ResultSet _currentResultSet;\r
117                 private DbDataReader _currentReader;\r
118                 private bool _nullParametersInPrepare;\r
119                 private bool _hasResultSet;\r
120                 private bool _explicitPrepare;\r
121 \r
122                 internal static ProcedureColumnCache _procedureColumnCache = new ProcedureColumnCache();\r
123 \r
124                 #endregion // Fields\r
125 \r
126                 #region Constructors\r
127 \r
128                 public AbstractDbCommand(\r
129                         String cmdText,\r
130                         AbstractDBConnection connection,\r
131                         AbstractTransaction transaction)\r
132                 {\r
133                         _connection = connection;\r
134                         base.CommandText = cmdText;\r
135                         _transaction = transaction;\r
136                         _isCommandPrepared = false;\r
137                         _explicitPrepare = false;\r
138                         _recordsAffected = -1;\r
139                         if (connection != null) {\r
140                                 connection.AddReference(this);\r
141                         }\r
142                 }\r
143 \r
144                 #endregion // Constructors\r
145 \r
146                 #region Properties\r
147 \r
148                 protected override DbParameterCollection DbParameterCollection\r
149                 {\r
150                         get {\r
151                                 if (_parameters == null) {\r
152                                         _parameters = CreateParameterCollection(this);\r
153                                 }\r
154                                 return _parameters; \r
155                         }\r
156                 }\r
157 \r
158                 protected override DbConnection DbConnection\r
159                 {\r
160                         get { return (DbConnection)_connection; }\r
161                         set {\r
162                                 if (value == _connection) {\r
163                                         return;\r
164                                 }\r
165 \r
166                                 if (_currentReader != null && !_currentReader.IsClosed) {\r
167                                         throw ExceptionHelper.ConnectionIsBusy(this.GetType().Name,((AbstractDBConnection)_connection).InternalState);\r
168                                 }\r
169                                 if (_connection != null) {\r
170                                         _connection.RemoveReference(this);\r
171                                 }\r
172                                 _connection = (AbstractDBConnection) value;\r
173                                 if (_connection != null) {\r
174                                         _connection.AddReference(this);\r
175                                 }\r
176                         }\r
177                 }\r
178 \r
179                 protected override DbTransaction DbTransaction\r
180                 {\r
181                         get { return _transaction != null ? _transaction.ActiveTransaction : null; }\r
182                         set { _transaction = (AbstractTransaction)value; }\r
183                 }\r
184 \r
185                 public override string CommandText\r
186                 {\r
187                         get { return base.CommandText; }\r
188                         set { \r
189                                 if (CommandText == null || String.Compare(CommandText, value,  true) != 0) {\r
190                                         base.CommandText = value;\r
191                                         _isCommandPrepared = false;\r
192                                         _explicitPrepare = false;\r
193                                 }\r
194                         }\r
195                 }\r
196 \r
197                 internal CommandBehavior Behavior\r
198                 {\r
199                         get { return _behavior; }\r
200                         set { _behavior = value; }\r
201                 }\r
202 \r
203                 bool IsCommandPrepared\r
204                 {\r
205                         get { return _isCommandPrepared; }\r
206                         set { _isCommandPrepared = value; }\r
207                 }\r
208 \r
209                 bool NullParametersInPrepare\r
210                 {\r
211                         get { return _nullParametersInPrepare; }\r
212                         set { _nullParametersInPrepare = value; }\r
213                 }\r
214 \r
215                 protected ArrayList InternalParameters\r
216                 {\r
217                         get {\r
218                                 if (_internalParameters == null) {\r
219                                         _internalParameters = new ArrayList();\r
220                                 }\r
221                                 return _internalParameters;\r
222                         }\r
223                 }\r
224 \r
225                 // Number of records affected by execution of batch statement\r
226                 // -1 for SELECT statements.\r
227                 internal int RecordsAffected\r
228                 {\r
229                         get {\r
230                                 return _recordsAffected;\r
231                         }\r
232                 }\r
233 \r
234                 // AbstractDbCommand acts as IEnumerator over JDBC statement\r
235                 // AbstractDbCommand.CurrentResultSet corresponds to IEnumerator.Current\r
236                 internal virtual ResultSet CurrentResultSet\r
237                 {\r
238                         get { \r
239                                 try {\r
240                                         if (_currentResultSet == null && _hasResultSet) {\r
241                                                 _currentResultSet = _statement.getResultSet(); \r
242                                         }\r
243                                         return _currentResultSet;\r
244                                 }\r
245                                 catch(SQLException e) {\r
246                                         throw new Exception(e.Message, e);\r
247                                 }\r
248                         }\r
249                 }\r
250 \r
251                 internal java.sql.Statement JdbcStatement\r
252                 {\r
253                         get { return _statement; }\r
254                 }\r
255 #if USE_DOTNET_REGEX\r
256                 protected virtual Regex StoredProcedureRegExp\r
257 #else\r
258                 protected virtual Pattern StoredProcedureRegExp\r
259 #endif\r
260                 {\r
261                         get { return SqlStatementsHelper.SimpleParameterStoredProcedureRegExp; }\r
262                 }\r
263 \r
264                 protected virtual SimpleRegex ParameterRegExp\r
265                 {\r
266                         get { return SqlStatementsHelper.SimpleParameterRegExp; }\r
267                 }\r
268 \r
269                 #endregion // Properties\r
270 \r
271                 #region Methods\r
272 \r
273                 protected abstract DbParameter CreateParameterInternal();\r
274 \r
275                 protected abstract void CheckParameters();\r
276 \r
277                 protected abstract DbDataReader CreateReader();\r
278 \r
279                 protected abstract DbParameterCollection CreateParameterCollection(AbstractDbCommand parent);\r
280 \r
281                 protected abstract SystemException CreateException(SQLException e);\r
282 \r
283                 protected internal void CopyTo(AbstractDbCommand target)\r
284                 {\r
285                         target._behavior = _behavior;\r
286                         target.CommandText = CommandText;\r
287                         target.CommandTimeout = CommandTimeout;\r
288                         target.CommandType = CommandType;\r
289                         target._connection = _connection;\r
290                         target._transaction = _transaction;\r
291                         target.UpdatedRowSource = UpdatedRowSource;\r
292 \r
293                         if (Parameters != null && Parameters.Count > 0) {\r
294                                 target._parameters = CreateParameterCollection(target);\r
295                                 for(int i=0 ; i < Parameters.Count; i++) {\r
296                                         target.Parameters.Add(((AbstractDbParameter)Parameters[i]).Clone());\r
297                                 }\r
298                         }\r
299                 }\r
300 \r
301                 public override void Cancel()\r
302                 {\r
303                         try {\r
304                                 if (_statement != null)\r
305                                         _statement.cancel();\r
306                         }\r
307                         catch {\r
308                                 // MSDN says : "If there is nothing to cancel, nothing happens. \r
309                                 // However, if there is a command in process, and the attempt to cancel fails, \r
310                                 // no exception is generated."\r
311                         }\r
312                 }\r
313                 \r
314                 protected virtual bool SkipParameter(DbParameter parameter)\r
315                 {\r
316                         return false;\r
317                 }\r
318 \r
319                 protected override DbParameter CreateDbParameter()\r
320                 {\r
321                         return CreateParameterInternal();\r
322                 }\r
323 \r
324                 internal void DeriveParameters ()\r
325                 {\r
326                         if(CommandType != CommandType.StoredProcedure) {\r
327                                 throw ExceptionHelper.DeriveParametersNotSupported(this.GetType(),CommandType);\r
328                         }\r
329 \r
330                         ArrayList parameters = DeriveParameters(CommandText, true);\r
331                         Parameters.Clear();\r
332                         foreach (AbstractDbParameter param in parameters) {\r
333                                 Parameters.Add(param.Clone());\r
334                         }\r
335                 }\r
336 \r
337                 protected ArrayList DeriveParameters(string procedureName, bool throwIfNotExist)\r
338                 {\r
339                         try {\r
340                                 ArrayList col = _procedureColumnCache.GetProcedureColumns((AbstractDBConnection)Connection, procedureName, this);\r
341                                 if (col == null) {\r
342                                         if (throwIfNotExist)\r
343                                                 throw ExceptionHelper.NoStoredProcedureExists(procedureName);\r
344                                         col = new ArrayList();\r
345                                 }\r
346 \r
347                                 return col;\r
348                         }\r
349                         catch(SQLException e) {\r
350                                 throw CreateException(e);\r
351                         }\r
352                 }\r
353 \r
354                 string CreateTableDirectCommandText(string tableNames) {\r
355                         string forBrowse = String.Empty;\r
356                         if ((Behavior & CommandBehavior.KeyInfo) != 0) {\r
357                                 AbstractDBConnection connection = (AbstractDBConnection)Connection;\r
358                                 if (connection != null) {\r
359                                         string dbname = connection.JdbcConnection.getMetaData().getDatabaseProductName();\r
360                                         if (dbname == "Microsoft SQL Server")   //must add "FOR BROWSE" for selects\r
361                                                 forBrowse = " FOR BROWSE";\r
362                                 }\r
363                         }\r
364 \r
365                         string[] names = tableNames.Split(',');\r
366                         StringBuilder sb = new StringBuilder();\r
367 \r
368                         for(int i = 0; i < names.Length; i++) {\r
369                                 sb.Append("SELECT * FROM ");\r
370                                 sb.Append(names[i]);\r
371                                 sb.Append(forBrowse);\r
372                                 sb.Append(';');\r
373                         }\r
374                                 \r
375                         if(names.Length <= 1) {\r
376                                 sb.Remove(sb.Length - 1,1);\r
377                         }\r
378                         return sb.ToString();\r
379                 }\r
380 \r
381                 private string PrepareCommandTextAndParameters()\r
382                 {\r
383                         NullParametersInPrepare = false;\r
384                         switch (CommandType) {\r
385                                 case CommandType.TableDirect :\r
386                                         return CreateTableDirectCommandText(CommandText);\r
387                                 case CommandType.StoredProcedure :\r
388                                         return CreateStoredProcedureCommandTextSimple(CommandText, Parameters, DeriveParameters(CommandText, false));\r
389                                 case CommandType.Text :\r
390 \r
391                                         int userParametersPosition = 0;\r
392                                         int charsConsumed = 0;\r
393                                         StringBuilder sb = new StringBuilder(CommandText.Length);\r
394 \r
395                                         for (SimpleMatch match = SqlStatementsHelper.CompoundStatementSplitterReqExp.Match(CommandText);\r
396                                                 match.Success;\r
397                                                 match = match.NextMatch()) {\r
398 \r
399                                                 int length = match.Length;\r
400 \r
401                                                 if (length == 0)\r
402                                                         continue;\r
403 \r
404                                                 int start = match.Index;\r
405                                                 string value = match.Value;\r
406 \r
407                                                 sb.Append(CommandText, charsConsumed, start-charsConsumed);\r
408                                                 charsConsumed = start + length;\r
409 \r
410 #if USE_DOTNET_REGEX\r
411                                                 Match storedProcMatch = StoredProcedureRegExp.Match(value);\r
412                                                 // count parameters for all kinds of simple statements \r
413                                                 userParametersPosition +=\r
414                                                         (storedProcMatch.Success) ?\r
415                                                         // statement is stored procedure call\r
416                                                         CreateStoredProcedureCommandText(sb, value, storedProcMatch, Parameters, userParametersPosition) :\r
417                                                         // statement is a simple SQL query                              \r
418                                                         PrepareSimpleQuery(sb, value, Parameters, userParametersPosition);      \r
419 #else\r
420                                                 Matcher storedProcMatch = StoredProcedureRegExp.matcher((java.lang.CharSequence)(object)value);\r
421                                                 userParametersPosition +=\r
422                                                         (storedProcMatch.find()) ?\r
423                                                         // statement is stored procedure call\r
424                                                         CreateStoredProcedureCommandText(sb, value, storedProcMatch, Parameters, userParametersPosition) :\r
425                                                         // statement is a simple SQL query                              \r
426                                                         PrepareSimpleQuery(sb, value, Parameters, userParametersPosition);\r
427 #endif\r
428                                         }\r
429 \r
430                                         sb.Append(CommandText, charsConsumed, CommandText.Length-charsConsumed);\r
431 \r
432                                         return sb.ToString();\r
433                         }\r
434                         return null;\r
435                 }\r
436 \r
437                 string CreateStoredProcedureCommandTextSimple(string procedureName, IDataParameterCollection userParams, IList derivedParams) {\r
438                         StringBuilder sb = new StringBuilder();\r
439 \r
440                         int curUserPos = 0;\r
441                         int curDerivedPos = 0;\r
442                         bool addParas = true;\r
443                         string trimedProcedureName = (procedureName != null) ? procedureName.TrimEnd() : String.Empty;\r
444                         if (trimedProcedureName.Length > 0 && trimedProcedureName[trimedProcedureName.Length-1] == ')')\r
445                                 addParas = false;\r
446                         \r
447                         if (derivedParams.Count > 0 && ((AbstractDbParameter)derivedParams[curDerivedPos]).Direction == ParameterDirection.ReturnValue) {\r
448                                 AbstractDbParameter derivedParam = (AbstractDbParameter)derivedParams[curDerivedPos++];\r
449 \r
450                                 AbstractDbParameter userParameter = GetUserParameter(derivedParam.Placeholder, userParams, curUserPos);\r
451                                 if (userParameter != null && userParameter.Direction == ParameterDirection.ReturnValue) {\r
452                                         curUserPos++;\r
453                                         InternalParameters.Add(userParameter);\r
454                                         sb.Append("{? = call ");\r
455 \r
456                                         if (derivedParam != null && !userParameter.IsDbTypeSet) {\r
457                                                 userParameter.JdbcType = derivedParam.JdbcType;\r
458                                         }\r
459                                 }\r
460                                 else {\r
461                                         sb.Append("{call ");\r
462                                 }\r
463                         }\r
464                         else {\r
465                                 if (userParams.Count > 0 && \r
466                                         ((AbstractDbParameter)userParams[0]).Direction == ParameterDirection.ReturnValue) {\r
467                                         curUserPos++;\r
468                                         InternalParameters.Add(userParams[0]);\r
469                                         sb.Append("{? = call ");\r
470                                 }\r
471                                 else\r
472                                         sb.Append("{call ");\r
473                         }\r
474 \r
475                         sb.Append(procedureName);\r
476                         if (addParas)\r
477                                 sb.Append('(');\r
478 \r
479                         bool needComma = false;\r
480                         for (int i = curDerivedPos; i < derivedParams.Count; i++) {\r
481                                 AbstractDbParameter derivedParameter = (AbstractDbParameter)derivedParams[curDerivedPos++];\r
482                                 \r
483                                 bool addParam = false;\r
484 \r
485                                 if (derivedParameter.IsSpecial) {\r
486                                         // derived parameter is special - never appears in user parameters or user values\r
487                                         InternalParameters.Add((AbstractDbParameter)derivedParameter.Clone());\r
488                                         addParam = true;\r
489                                 }\r
490                                 else {\r
491                                         AbstractDbParameter userParameter = GetUserParameter(derivedParameter.Placeholder, userParams, curUserPos);\r
492                                         if (userParameter != null) {\r
493                                                 curUserPos++;\r
494                                                 InternalParameters.Add(userParameter);\r
495                                                 addParam = true;\r
496 \r
497                                                 if (derivedParameter != null && !userParameter.IsDbTypeSet) {\r
498                                                         userParameter.JdbcType = derivedParameter.JdbcType;\r
499                                                 }\r
500                                         }\r
501                                 }\r
502 \r
503                                 if (addParam) {\r
504                                         if (needComma)\r
505                                                 sb.Append(',');\r
506                                         else\r
507                                                 needComma = true;\r
508 \r
509                                         sb.Append('?');\r
510                                 }\r
511                         }\r
512 \r
513                         for (int i = curUserPos; i < userParams.Count; i++) {\r
514                                 if (needComma)\r
515                                         sb.Append(',');\r
516                                 else\r
517                                         needComma = true;\r
518 \r
519                                 AbstractDbParameter userParameter = (AbstractDbParameter)userParams[curUserPos++];\r
520                                 InternalParameters.Add(userParameter);\r
521 \r
522                                 sb.Append('?');\r
523                         }\r
524 \r
525                         if (addParas)\r
526                                 sb.Append(')');\r
527                         sb.Append('}');\r
528                         return sb.ToString();\r
529                 }\r
530 \r
531                 /// <summary>\r
532                 /// We suppose that user parameters are in the same order as devived parameters except the special cases\r
533                 /// (return value, oracle ref cursors etc.)\r
534                 /// </summary>\r
535                 //protected virtual string CreateStoredProcedureCommandText(string procedureName, IList userParametersList, int userParametersListStart/*, int userParametersListCount*/, string[] userValuesList, ArrayList derivedParametersList)\r
536 #if USE_DOTNET_REGEX\r
537                 int CreateStoredProcedureCommandText(StringBuilder sb, string sql, Match match, IDataParameterCollection userParams, int userParamsStartPosition)\r
538 #else\r
539                 int CreateStoredProcedureCommandText(StringBuilder sb, string sql, Matcher match, IDataParameterCollection userParams, int userParamsStartPosition)\r
540 #endif\r
541                 {\r
542                         int curUserPos = userParamsStartPosition;\r
543 #if USE_DOTNET_REGEX\r
544                         Group procNameGroup = null;\r
545 \r
546                         for (Match procNameMatch = match; procNameMatch.Success; procNameMatch = procNameMatch.NextMatch()){\r
547                                 procNameGroup = match.Groups["PROCNAME"];\r
548                                 if (!procNameGroup.Success) {\r
549                                         continue;\r
550                                 }\r
551                         }\r
552 \r
553                         if (procNameGroup == null || !procNameGroup.Success)\r
554                                 throw new ArgumentException("Not a stored procedure call: '{0}'", sql);\r
555 \r
556                         ArrayList derivedParameters = DeriveParameters(procNameGroup.Value, false);\r
557 #else\r
558                         ArrayList derivedParameters = DeriveParameters(match.group(2).Trim(), false);\r
559 #endif\r
560                         int curDerivedPos = 0;\r
561 \r
562                         AbstractDbParameter retValderivedParameter = curDerivedPos < derivedParameters.Count ?\r
563                                 (AbstractDbParameter)derivedParameters[curDerivedPos] : null;\r
564                         if (retValderivedParameter != null && retValderivedParameter.Direction == ParameterDirection.ReturnValue)\r
565                                 curDerivedPos++;\r
566 \r
567                         int queryCurrentPosition = 0;\r
568                         \r
569 #if USE_DOTNET_REGEX\r
570                         for (Match retValMatch = match; retValMatch.Success; retValMatch = retValMatch.NextMatch()){\r
571                                 Group retval = retValMatch.Groups["RETVAL"];\r
572                                 if (!retval.Success) {\r
573                                         continue;\r
574                                 }\r
575 \r
576                                 int retvalIndex = retval.Index;\r
577                                 string retvalValue = retval.Value;\r
578                                 int retvalLength = retval.Length;\r
579 #else\r
580                         int retvalIndex = match.start(1);\r
581                         for (;retvalIndex >= 0;) {\r
582                                 string retvalValue = match.group(1);\r
583                                 int retvalLength = retvalValue.Length;\r
584 #endif\r
585 \r
586                                 sb.Append(sql, queryCurrentPosition, retvalIndex);\r
587                                 AbstractDbParameter userParameter = GetUserParameter(retvalValue, userParams, curUserPos);\r
588                                 if (userParameter != null) {\r
589                                         sb.Append('?');\r
590                                         InternalParameters.Add(userParameter);\r
591 \r
592                                         if (retValderivedParameter != null && !userParameter.IsDbTypeSet) {\r
593                                                 userParameter.JdbcType = retValderivedParameter.JdbcType;\r
594                                         }\r
595 \r
596                                         curUserPos++;\r
597                                 }\r
598                                 else {\r
599                                         sb.Append(retvalValue);\r
600                                 }\r
601 \r
602                                 queryCurrentPosition = (retvalIndex + retvalLength);\r
603 \r
604                                 break;\r
605                         }\r
606 \r
607 #if USE_DOTNET_REGEX\r
608                         sb.Append(sql, queryCurrentPosition, procNameGroup.Index + procNameGroup.Length - queryCurrentPosition);\r
609                         queryCurrentPosition = procNameGroup.Index + procNameGroup.Length;\r
610 #else\r
611                         sb.Append(sql, queryCurrentPosition, match.end(2) - queryCurrentPosition);\r
612                         queryCurrentPosition = match.end(2);\r
613 #endif\r
614 \r
615                         bool hasUserParams = false;\r
616 \r
617 #if USE_DOTNET_REGEX\r
618                         must rewrite the regex to not parse params to have single code with java regex\r
619 #else\r
620                         int paramsStart = match.start(3);\r
621                         if (paramsStart >= 0) {\r
622 #endif\r
623 \r
624                                 hasUserParams = true;\r
625                                 sb.Append(sql,queryCurrentPosition,paramsStart - queryCurrentPosition);\r
626                                 queryCurrentPosition = paramsStart;\r
627 \r
628                                 for (SimpleMatch m = SqlStatementsHelper.ProcedureParameterSplitterReqExp.Match(match.group(3));\r
629                                         m.Success;m = m.NextMatch()) {\r
630 \r
631                                         SimpleCapture parameterCapture = m;\r
632                                         sb.Append(sql,queryCurrentPosition,paramsStart + parameterCapture.Index - queryCurrentPosition);\r
633 \r
634                                         // advance in query\r
635                                         queryCurrentPosition = paramsStart + parameterCapture.Index + parameterCapture.Length;\r
636 \r
637                                         AbstractDbParameter derivedParameter = curDerivedPos < derivedParameters.Count ?\r
638                                                 (AbstractDbParameter)derivedParameters[curDerivedPos++] : null;\r
639                                         \r
640                                         //check for special params\r
641                                         while (derivedParameter != null && derivedParameter.IsSpecial) {\r
642                                                 // derived parameter is special - never appears in user parameters or user values\r
643                                                 InternalParameters.Add((AbstractDbParameter)derivedParameter.Clone());\r
644                                                 sb.Append('?');\r
645                                                 sb.Append(',');\r
646 \r
647                                                 derivedParameter = curDerivedPos < derivedParameters.Count ?\r
648                                                         (AbstractDbParameter)derivedParameters[curDerivedPos++] : null;\r
649                                         }\r
650 \r
651                                         AbstractDbParameter userParameter = GetUserParameter(parameterCapture.Value.Trim(), userParams, curUserPos);\r
652 \r
653                                         if (userParameter != null) {\r
654                                                 sb.Append('?');\r
655                                                 InternalParameters.Add(userParameter);\r
656                                                 if (derivedParameter != null && !userParameter.IsDbTypeSet) {\r
657                                                         userParameter.JdbcType = derivedParameter.JdbcType;\r
658                                                 }\r
659                                                 // advance in user parameters\r
660                                                 curUserPos++;                           \r
661                                         }\r
662                                         else {\r
663                                                 sb.Append(parameterCapture.Value);\r
664                                         }                                                                       \r
665                                 }                                       \r
666                         }\r
667 \r
668                         bool addedSpecialParams = false;\r
669 \r
670                         for (int i = curDerivedPos; i < derivedParameters.Count;) {\r
671                                 AbstractDbParameter derivedParameter = (AbstractDbParameter)derivedParameters[i++];\r
672                                 if (derivedParameter.IsSpecial) {\r
673                                         // derived parameter is special - never appears in user parameters or user values\r
674                                         if (!hasUserParams && !addedSpecialParams) {\r
675                                                 addedSpecialParams = true;\r
676                                                 curDerivedPos++;\r
677                                                 sb.Append('(');\r
678                                         }\r
679 \r
680                                         for (;curDerivedPos < i;curDerivedPos++)\r
681                                                 sb.Append(',');\r
682 \r
683                                         InternalParameters.Add((AbstractDbParameter)derivedParameter.Clone());\r
684                                         sb.Append('?');\r
685                                 }\r
686                         }\r
687 \r
688                         if (!hasUserParams && addedSpecialParams)\r
689                                 sb.Append(')');\r
690 \r
691                         sb.Append(sql,queryCurrentPosition,sql.Length - queryCurrentPosition);\r
692                         return curUserPos - userParamsStartPosition;\r
693                 }\r
694 \r
695                 protected virtual AbstractDbParameter GetUserParameter(string parameterName, IList userParametersList, int userParametersListPosition)\r
696                 {\r
697                         if (userParametersListPosition < userParametersList.Count) {\r
698                                 AbstractDbParameter param = (AbstractDbParameter)userParametersList[userParametersListPosition];\r
699                                 if (param.Placeholder == parameterName)\r
700                                         return param;\r
701                         }\r
702                         return null;\r
703                 }\r
704 \r
705                 int PrepareSimpleQuery(StringBuilder sb, string query, IList userParametersList, int userParametersListStart)\r
706                 {\r
707                         int queryCurrentPosition = 0;\r
708                         int userParametersListPosition = userParametersListStart;\r
709 \r
710                         if (userParametersList.Count > 0) {\r
711                                 for (SimpleMatch m = ParameterRegExp.Match(query);\r
712                                         m.Success;m = m.NextMatch()) {\r
713 \r
714                                         SimpleCapture parameterCapture = m;\r
715                                         sb.Append(query,queryCurrentPosition,parameterCapture.Index - queryCurrentPosition);\r
716 \r
717                                         // advance in query\r
718                                         queryCurrentPosition = parameterCapture.Index + parameterCapture.Length;        \r
719 \r
720                                         AbstractDbParameter userParameter = GetUserParameter(parameterCapture.Value, userParametersList, userParametersListPosition);\r
721 \r
722                                         if (userParameter != null) {\r
723                                                 if (IsNullParameter(userParameter)) {\r
724                                                         sb.Append("null");\r
725                                                         NullParametersInPrepare = true;\r
726                                                 }\r
727                                                 else {\r
728                                                         sb.Append('?');\r
729                                                         InternalParameters.Add(userParameter);  \r
730                                                 }       \r
731                                                 // advance in user parameters\r
732                                                 userParametersListPosition++;                           \r
733                                         }\r
734                                         else {\r
735                                                 sb.Append(parameterCapture.Value);\r
736                                         }\r
737                                 }\r
738                         }\r
739 \r
740                         sb.Append(query,queryCurrentPosition,query.Length - queryCurrentPosition);\r
741                         int userParamsConsumed = userParametersListPosition - userParametersListStart;\r
742 \r
743                         if ((Behavior & CommandBehavior.KeyInfo) == 0)\r
744                                 return userParamsConsumed;\r
745 \r
746                         AbstractDBConnection connection = (AbstractDBConnection)Connection;\r
747                         if (connection == null)\r
748                                 return userParamsConsumed;\r
749 \r
750                         string dbname = connection.JdbcConnection.getMetaData().getDatabaseProductName();\r
751                         if (dbname == "Microsoft SQL Server") { //must add "FOR BROWSE" for selects\r
752                                 if (SqlStatementsHelper.SelectFromStatementReqExp.IsMatch(query))\r
753                                         if (!SqlStatementsHelper.ForBrowseStatementReqExp.IsMatch(query))\r
754                                                 sb.Append(" FOR BROWSE");\r
755                         }\r
756 \r
757                         return userParamsConsumed;\r
758                 }\r
759 \r
760                 protected virtual bool IsNullParameter(AbstractDbParameter parameter)\r
761                 {\r
762                         return ((parameter.Value == null || parameter.Value == DBNull.Value) && !parameter.IsDbTypeSet);\r
763                 }\r
764 \r
765                 protected virtual void PrepareInternalParameters()\r
766                 {\r
767                         InternalParameters.Clear();\r
768                 }\r
769         \r
770                 protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)\r
771                 {\r
772                         AbstractDBConnection connection = (AbstractDBConnection)Connection;\r
773                         if (connection == null) {\r
774                                 throw ExceptionHelper.ConnectionNotInitialized("ExecuteReader");\r
775                         }\r
776 \r
777                         IDbTransaction transaction = Transaction;\r
778                         if ((transaction != null && transaction.Connection != connection) ||\r
779                                 (transaction == null && !connection.JdbcConnection.getAutoCommit())) {\r
780                                 throw ExceptionHelper.TransactionNotInitialized();\r
781                         }\r
782 \r
783                         connection.IsExecuting = true;\r
784 \r
785                         try {\r
786                                 Behavior = behavior;\r
787 \r
788                                 PrepareInternalParameters();                    \r
789                                 PrepareInternal();\r
790 \r
791                                 // For SchemaOnly there is no need for statement execution\r
792                                 if (Behavior != CommandBehavior.SchemaOnly) {\r
793                                         _recordsAffected = -1;\r
794 \r
795                                         if ((Behavior & CommandBehavior.SingleRow) != 0) {\r
796                                                 _statement.setMaxRows(1);\r
797                                         }\r
798                                 \r
799                                         if(_statement is PreparedStatement) {\r
800                                                 BindParameters(InternalParameters);\r
801                                                 _hasResultSet = ((PreparedStatement)_statement).execute();\r
802                                         }\r
803                                         else {\r
804                                                 _hasResultSet =_statement.execute(_javaCommandText);                                    \r
805                                         }\r
806                 \r
807                                         if (!_hasResultSet) {\r
808                                                 int updateCount = _statement.getUpdateCount();\r
809                                                 if (updateCount >= 0) {\r
810                                                         AccumulateRecordsAffected(updateCount);\r
811                                                         _hasResultSet = true; //play as if we have resultset\r
812                                                         NextResultSet();\r
813                                                 }\r
814                                         }                                       \r
815                                 }\r
816                                 connection.IsFetching = true;\r
817                                 try {\r
818                                         _currentReader = CreateReader();\r
819                                 }\r
820                                 catch(Exception e) {\r
821                                         connection.IsFetching = false;\r
822                                         throw e;\r
823                                 }\r
824                                 return _currentReader;\r
825                         }\r
826                         catch(SQLException e) {                         \r
827                                 throw CreateException(e);\r
828                         }\r
829                         finally {\r
830                                 connection.IsExecuting = false;\r
831                                 NullParametersInPrepare = false;\r
832                         }\r
833                 }\r
834 \r
835                 public override void Prepare()\r
836                 {\r
837                         ((AbstractDBConnection)Connection).IsExecuting = true;\r
838                         try {\r
839                                 CheckParameters();\r
840                                 _explicitPrepare = true;\r
841                         }\r
842                         finally {\r
843                                 ((AbstractDBConnection)Connection).IsExecuting = false;\r
844                         }\r
845                 }\r
846 \r
847                 private void PrepareInternal()\r
848                 {\r
849                         if ((Connection == null) || (Connection.State != ConnectionState.Open)) {\r
850                                 throw ExceptionHelper.ConnectionNotOpened("Prepare",(Connection != null) ? Connection.State.ToString() : "");\r
851                         }\r
852 \r
853                         if (IsCommandPrepared) {\r
854                                 // maybe we have to prepare the command again\r
855                                 bool hasNullParameters = false;\r
856                                 for(int i = 0; (i < Parameters.Count) && !hasNullParameters; i++) {\r
857                                         AbstractDbParameter parameter = (AbstractDbParameter)Parameters[i];\r
858                                         if (IsNullParameter(parameter)) {\r
859                                                 // if we still have null parameters - have to prepare agail\r
860                                                 IsCommandPrepared = false;\r
861                                                 hasNullParameters = true;\r
862                                         }\r
863                                 }\r
864 \r
865                                 if (!NullParametersInPrepare && hasNullParameters) {\r
866                                         // if we prepeared using null parameters and now there is no null parameters - need to prepare again\r
867                                         IsCommandPrepared = false;\r
868                                 }\r
869                         }\r
870 \r
871                         if (!IsCommandPrepared) {\r
872 \r
873                                 _javaCommandText = PrepareCommandTextAndParameters();\r
874 \r
875                                 java.sql.Connection jdbcCon = _connection.JdbcConnection;\r
876 \r
877                                 // For SchemaOnly we just prepare statement (for future use in GetSchemaTable)\r
878                                 if (Behavior == CommandBehavior.SchemaOnly) {\r
879                                         if (CommandType == CommandType.StoredProcedure)\r
880                                                 _statement = jdbcCon.prepareCall(_javaCommandText);\r
881                                         else\r
882                                                 _statement = jdbcCon.prepareStatement(_javaCommandText);        \r
883                                         return;\r
884                                 }\r
885 \r
886                                 if (CommandType == CommandType.StoredProcedure)\r
887                                         _statement = jdbcCon.prepareCall(_javaCommandText);\r
888                                 else {\r
889                                         int internalParametersCount = InternalParameters.Count;\r
890                                         if ( internalParametersCount > 0) {\r
891                                                 bool hasOnlyInputParameters = true;\r
892                                                 for(int i=0; i < internalParametersCount; i++) {\r
893                                                         AbstractDbParameter internalParameter = (AbstractDbParameter)InternalParameters[i];\r
894                                                         if (IsNullParameter(internalParameter)) {\r
895                                                                 NullParametersInPrepare = true;\r
896                                                         }\r
897 \r
898                                                         if ((internalParameter.Direction & ParameterDirection.Output) != 0){\r
899                                                                 hasOnlyInputParameters = false;\r
900                                                         }\r
901                                                 }\r
902 \r
903                                                 if (hasOnlyInputParameters) {\r
904                                                         _statement = jdbcCon.prepareStatement(_javaCommandText);        \r
905                                                 }\r
906                                                 else {                                          \r
907                                                         _statement = jdbcCon.prepareCall(_javaCommandText);\r
908                                                 }\r
909                                         }\r
910                                         else {\r
911                                                 if (_explicitPrepare) {\r
912                                                         _statement = jdbcCon.prepareStatement(_javaCommandText);                                \r
913                                                 }\r
914                                                 else {\r
915                                                         _statement = jdbcCon.createStatement();                                 \r
916                                                 }\r
917                                         }\r
918                                 }\r
919                                 IsCommandPrepared = true;\r
920                         }\r
921                 }\r
922 \r
923                 protected void BindParameters(ArrayList parameters)\r
924                 {\r
925                         for(int parameterIndex = 0; parameterIndex < parameters.Count; parameterIndex++) {\r
926                                 AbstractDbParameter parameter = (AbstractDbParameter)parameters[parameterIndex];\r
927                                 switch (parameter.Direction) {\r
928                                         case ParameterDirection.Input :\r
929                                                 BindInputParameter(parameter,parameterIndex);\r
930                                                 break;\r
931                                         case ParameterDirection.InputOutput:\r
932                                                 BindInputParameter(parameter,parameterIndex);\r
933                                                 BindOutputParameter(parameter,parameterIndex);\r
934                                                 break;\r
935                                         case ParameterDirection.Output :\r
936                                                 BindOutputParameter(parameter,parameterIndex);\r
937                                                 break;\r
938                                         case ParameterDirection.ReturnValue :\r
939                                                 BindOutputParameter(parameter,parameterIndex);\r
940                                                 break;\r
941                                 }\r
942                         }\r
943                 }\r
944                 \r
945                 protected virtual void BindInputParameter(AbstractDbParameter parameter, int parameterIndex)\r
946                 {\r
947                         object value = parameter.ConvertedValue;                        \r
948                         // java parameters are 1 based, while .net are 0 based\r
949                         parameterIndex++; \r
950                         PreparedStatement preparedStatement = ((PreparedStatement)_statement);\r
951 \r
952                         switch (parameter.JdbcType) {\r
953                                 case DbTypes.JavaSqlTypes.DATALINK:\r
954                                 case DbTypes.JavaSqlTypes.DISTINCT:\r
955                                 case DbTypes.JavaSqlTypes.JAVA_OBJECT:\r
956                                 case DbTypes.JavaSqlTypes.OTHER:\r
957                                 case DbTypes.JavaSqlTypes.REF:\r
958                                 case DbTypes.JavaSqlTypes.STRUCT: {\r
959                                         preparedStatement.setObject(parameterIndex, value, (int)parameter.JdbcType);\r
960                                         return;\r
961                                 }\r
962                         }\r
963 \r
964                         if ((value is DBNull) || (value == null)) {\r
965                                 preparedStatement.setNull(parameterIndex, (int)((AbstractDbParameter)parameter).JdbcType);\r
966                         }\r
967                         else if (value is long) {\r
968                                 preparedStatement.setLong(parameterIndex, (long)value);\r
969                         }\r
970                         else if (value is byte[]) {\r
971                                 if (((byte[])value).Length <= 4000) {\r
972                                         preparedStatement.setBytes(parameterIndex, vmw.common.TypeUtils.ToSByteArray((byte[]) value));\r
973                                 }\r
974                                 else {\r
975                                         InputStream iStream=new ByteArrayInputStream(vmw.common.TypeUtils.ToSByteArray((byte[]) value));\r
976                                         preparedStatement.setBinaryStream(parameterIndex,iStream,((byte[])value).Length);\r
977                                 }\r
978                         }\r
979                         else if (value is byte) {\r
980                                 preparedStatement.setByte(parameterIndex, (sbyte)(byte)value);\r
981                         }\r
982                         else if (value is char[]) {\r
983                                 Reader reader = new CharArrayReader((char[])value);\r
984                                 preparedStatement.setCharacterStream(parameterIndex,reader,((char[])value).Length);\r
985                         }\r
986                         else if (value is bool) {\r
987                                 preparedStatement.setBoolean(parameterIndex, (bool) value);\r
988                         }\r
989                         else if (value is char) {\r
990                                 preparedStatement.setString(parameterIndex, ((char)value).ToString());\r
991                         }\r
992                         else if (value is DateTime) {\r
993                                 switch (parameter.JdbcType) {\r
994                                         default:\r
995                                         case DbTypes.JavaSqlTypes.TIMESTAMP:\r
996                                                 preparedStatement.setTimestamp(parameterIndex,DbConvert.ClrTicksToJavaTimestamp(((DateTime)value).Ticks));\r
997                                                 break;\r
998                                         case DbTypes.JavaSqlTypes.TIME:\r
999                                                 preparedStatement.setTime(parameterIndex,DbConvert.ClrTicksToJavaTime(((DateTime)value).Ticks));\r
1000                                                 break;\r
1001                                         case DbTypes.JavaSqlTypes.DATE:\r
1002                                                 preparedStatement.setDate(parameterIndex,DbConvert.ClrTicksToJavaDate(((DateTime)value).Ticks));\r
1003                                                 break;\r
1004                                 }\r
1005                         }\r
1006                         else if (value is TimeSpan) {\r
1007                                 if (parameter.JdbcType == DbTypes.JavaSqlTypes.TIMESTAMP)\r
1008                                         preparedStatement.setTimestamp(parameterIndex,DbConvert.ClrTicksToJavaTimestamp(((TimeSpan)value).Ticks));\r
1009                                 else\r
1010                                         preparedStatement.setTime(parameterIndex,DbConvert.ClrTicksToJavaTime(((TimeSpan)value).Ticks));\r
1011                         }\r
1012                         else if (value is Decimal) {\r
1013                                 preparedStatement.setBigDecimal(parameterIndex, vmw.common.PrimitiveTypeUtils.DecimalToBigDecimal((Decimal) value));\r
1014                         }\r
1015                         else if (value is double) {\r
1016                                 preparedStatement.setDouble(parameterIndex, (double)value);\r
1017                         }\r
1018                         else if (value is float) {\r
1019                                 preparedStatement.setFloat(parameterIndex, (float)value);\r
1020                         }\r
1021                         else if (value is int) {\r
1022                                 preparedStatement.setInt(parameterIndex, (int)value);\r
1023                         }\r
1024                         else if (value is string) {\r
1025                                 preparedStatement.setString(parameterIndex, (string)value);\r
1026                         }\r
1027                         else if (value is Guid) {\r
1028                                 preparedStatement.setString(parameterIndex, value.ToString());\r
1029                         }\r
1030                         else if (value is short) {\r
1031                                 preparedStatement.setShort(parameterIndex, (short)value);\r
1032                         }\r
1033                         else if (value is sbyte) {\r
1034                                 preparedStatement.setByte(parameterIndex, (sbyte)value);\r
1035                         }\r
1036                         else {\r
1037                                 preparedStatement.setObject(parameterIndex, value);\r
1038                         }\r
1039                 }\r
1040 \r
1041                 protected virtual void BindOutputParameter(AbstractDbParameter parameter, int parameterIndex)
1042                 {
1043                         parameter.Validate();
1044                         int jdbcType = (int)parameter.JdbcType;         \r
1045                         // java parameters are 1 based, while .net are 0 based\r
1046                         parameterIndex++;\r
1047 \r
1048                         CallableStatement callableStatement = ((CallableStatement)_statement);\r
1049 \r
1050                         // the scale has a meening only in DECIMAL and NUMERIC parameters\r
1051                         if (jdbcType == Types.DECIMAL || jdbcType == Types.NUMERIC) {\r
1052                                 if(parameter.DbType == DbType.Currency) {\r
1053                                         callableStatement.registerOutParameter(parameterIndex, jdbcType, 4);\r
1054                                 }\r
1055                                 else {\r
1056                                         callableStatement.registerOutParameter(parameterIndex, jdbcType, parameter.Scale);\r
1057                                 }\r
1058                         }\r
1059                         else {\r
1060                                 callableStatement.registerOutParameter(parameterIndex, jdbcType);\r
1061                         }
1062                 }\r
1063 \r
1064                 private void FillOutputParameters()
1065                 {       
1066                         if  (!(_statement is CallableStatement)) {
1067                                 return;
1068                         }
1069                         for(int i = 0; i < InternalParameters.Count; i++) {
1070                                 AbstractDbParameter parameter = (AbstractDbParameter)InternalParameters[i];
1071                                 ParameterDirection direction = parameter.Direction;
1072                                 if (((direction & ParameterDirection.Output) != 0) && !SkipParameter(parameter)) {                                      
1073                                         FillOutputParameter(parameter, i);
1074                                 }
1075                                 // drop jdbc type of out parameter, since it possibly was updated in ExecuteReader
1076                                 parameter.IsJdbcTypeSet = false;
1077                         }
1078                 }\r
1079 \r
1080                 protected virtual void FillOutputParameter(DbParameter parameter, int index)\r
1081                 {                       \r
1082                         CallableStatement callableStatement = (CallableStatement)_statement;\r
1083                         ParameterMetadataWrapper parameterMetadataWrapper = null; \r
1084                         // FIXME wait for other drivers to implement\r
1085 //                      try {\r
1086 //                              parameterMetadataWrapper = new ParameterMetadataWrapper(callableStatement.getParameterMetaData());\r
1087 //                      }\r
1088 //                      catch {\r
1089 //                              // suppress error : ms driver for sql server does not implement getParameterMetaData\r
1090 //                              // suppress exception : ms driver for sql server does not implement getParameterMetaData\r
1091 //                      }\r
1092                         DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes)((AbstractDbParameter)parameter).JdbcType;\r
1093                         try {\r
1094                                 parameter.Value = DbConvert.JavaResultSetToClrWrapper(callableStatement,index,javaSqlType,parameter.Size,parameterMetadataWrapper);\r
1095                         }\r
1096                         catch(java.sql.SQLException e) {\r
1097                                 throw CreateException(e);\r
1098                         }\r
1099                 }\r
1100 \r
1101                 // AbstractDbCommand acts as IEnumerator over JDBC statement\r
1102                 // AbstractDbCommand.NextResultSet corresponds to IEnumerator.MoveNext\r
1103                 internal virtual bool NextResultSet()\r
1104                 {\r
1105                         if (!_hasResultSet)\r
1106                                 return false;\r
1107 \r
1108                         try {\r
1109                                 for(;;) {\r
1110                                         _hasResultSet = _statement.getMoreResults();\r
1111                                         if (_hasResultSet)\r
1112                                                 return true;\r
1113                                         int updateCount = _statement.getUpdateCount();\r
1114                                         if (updateCount < 0)\r
1115                                                 return false;\r
1116 \r
1117                                         AccumulateRecordsAffected(updateCount); \r
1118                                 }\r
1119                         }\r
1120                         catch (SQLException e) {\r
1121                                 throw CreateException(e);\r
1122                         }\r
1123                         finally {\r
1124                                 _currentResultSet = null;\r
1125                         }\r
1126                 }\r
1127 \r
1128                 private void AccumulateRecordsAffected(int updateCount)\r
1129                 { \r
1130                         if (_recordsAffected < 0) {\r
1131                                 _recordsAffected = updateCount;\r
1132                         }\r
1133                         else {\r
1134                                 _recordsAffected += updateCount;\r
1135                         }\r
1136                 }\r
1137 \r
1138                 internal void OnReaderClosed(object reader)\r
1139                 {\r
1140                         CloseInternal();\r
1141                         if (Connection != null) {\r
1142                                 ((AbstractDBConnection)Connection).RemoveReference(reader);\r
1143                                 ((AbstractDBConnection)Connection).IsFetching = false;\r
1144                                 if ((Behavior & CommandBehavior.CloseConnection) != 0) {\r
1145                                         Connection.Close();\r
1146                                 }\r
1147                         }                       \r
1148                 }\r
1149 \r
1150                 internal void CloseInternal()\r
1151                 {\r
1152                         if (Behavior != CommandBehavior.SchemaOnly) {\r
1153                                 if (_statement != null) {\r
1154                                         while (NextResultSet()) {\r
1155                                         }                                                       \r
1156                                         FillOutputParameters();                         \r
1157                                 }\r
1158                         }\r
1159                         _currentReader = null;\r
1160                         CleanUp();\r
1161                 }\r
1162 \r
1163                 protected override void Dispose(bool disposing)\r
1164                 {\r
1165                         if (disposing) {\r
1166                                 CleanUp();\r
1167                         }\r
1168                         base.Dispose(disposing);\r
1169                 }\r
1170 \r
1171                 private void CleanUp()\r
1172                 {\r
1173                         if (_currentReader != null) {\r
1174                                 // we must preserve statement object until we have an associated reader object that might access it.\r
1175                                 return;\r
1176                         }\r
1177                         if (Connection != null) {\r
1178                                 ((AbstractDBConnection)Connection).RemoveReference(this);\r
1179                         }\r
1180                         if (_statement != null) {\r
1181                                 _statement.close();\r
1182                                 _statement = null;\r
1183                         }                               \r
1184                         IsCommandPrepared = false;\r
1185                         _internalParameters = null;\r
1186                         _currentResultSet = null;\r
1187                 }\r
1188 \r
1189                 internal void OnSchemaChanging()\r
1190                 {\r
1191                 }\r
1192 \r
1193                 #endregion // Methods\r
1194         }\r
1195 }\r