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