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