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