Remove some deprecated libraries
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Common / StatementBase.cs
1 /*
2  *      Firebird ADO.NET Data provider for .NET and Mono 
3  * 
4  *         The contents of this file are subject to the Initial 
5  *         Developer's Public License Version 1.0 (the "License"); 
6  *         you may not use this file except in compliance with the 
7  *         License. You may obtain a copy of the License at 
8  *         http://www.firebirdsql.org/index.php?op=doc&id=idpl
9  *
10  *         Software distributed under the License is distributed on 
11  *         an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
12  *         express or implied. See the License for the specific 
13  *         language governing rights and limitations under the License.
14  * 
15  *      Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16  *      All Rights Reserved.
17  */
18
19 using System;
20 using System.Text;
21 using System.Data;
22
23 namespace FirebirdSql.Data.Common
24 {
25         #region Enumerations
26
27         internal enum StatementState
28         {
29                 Deallocated,
30                 Allocated,
31                 Prepared,
32                 Executed,
33                 Closed,
34                 Error
35         }
36
37         #endregion
38
39         internal abstract class StatementBase : IDisposable
40         {
41                 #region Protected Static Fields
42
43                 // Plan information     items
44                 protected static byte[] DescribePlanInfoItems = new byte[] 
45                 { 
46                         IscCodes.isc_info_sql_get_plan
47                 };
48
49                 // Records affected     items
50                 protected static byte[] RecordsAffectedInfoItems = new byte[]
51                 {
52                         IscCodes.isc_info_sql_records
53                 };
54
55                 // Describe     information     items
56                 protected static byte[] DescribeInfoItems = new byte[] 
57                 { 
58                         IscCodes.isc_info_sql_select,
59                         IscCodes.isc_info_sql_describe_vars,
60                         IscCodes.isc_info_sql_sqlda_seq,
61                         IscCodes.isc_info_sql_type,
62                         IscCodes.isc_info_sql_sub_type,
63                         IscCodes.isc_info_sql_length,
64                         IscCodes.isc_info_sql_scale,
65                         IscCodes.isc_info_sql_field,
66                         IscCodes.isc_info_sql_relation,
67                         // IscCodes.isc_info_sql_owner,
68                         IscCodes.isc_info_sql_alias,
69                         IscCodes.isc_info_sql_describe_end
70                 };
71
72                 protected static byte[] DescribeBindInfoItems = new byte[] 
73                 { 
74                         IscCodes.isc_info_sql_bind,
75                         IscCodes.isc_info_sql_describe_vars,
76                         IscCodes.isc_info_sql_sqlda_seq,
77                         IscCodes.isc_info_sql_type,
78                         IscCodes.isc_info_sql_sub_type,
79                         IscCodes.isc_info_sql_length,
80                         IscCodes.isc_info_sql_scale,
81                         IscCodes.isc_info_sql_field,
82                         IscCodes.isc_info_sql_relation,
83                         // IscCodes.isc_info_sql_owner,
84                         IscCodes.isc_info_sql_alias,
85                         IscCodes.isc_info_sql_describe_end 
86                 };
87
88                 protected static byte[] StatementTypeInfoItems = new byte[]
89                 {
90                         IscCodes.isc_info_sql_stmt_type
91                 };
92
93                 #endregion
94
95                 #region Fields
96
97                 private bool disposed;
98
99                 #endregion
100
101                 #region Abstract Properties
102
103                 public abstract IDatabase DB
104                 {
105                         get;
106                         set;
107                 }
108
109                 public abstract ITransaction Transaction
110                 {
111                         get;
112                         set;
113                 }
114
115                 public abstract Descriptor Parameters
116                 {
117                         get;
118                         set;
119                 }
120
121                 public abstract Descriptor Fields
122                 {
123                         get;
124                 }
125
126                 public abstract int RecordsAffected
127                 {
128                         get;
129                 }
130
131                 public abstract bool IsPrepared
132                 {
133                         get;
134                 }
135
136                 public abstract DbStatementType StatementType
137                 {
138                         get;
139                         set;
140                 }
141
142                 public abstract StatementState State
143                 {
144                         get;
145                         set;
146                 }
147
148                 public abstract int FetchSize
149                 {
150                         get;
151                         set;
152                 }
153
154                 #endregion
155
156                 #region Protected Properties
157
158                 protected bool IsDisposed
159                 {
160                         get { return this.disposed; }
161                 }
162
163                 #endregion
164
165                 #region Protected Fields
166
167                 protected TransactionUpdateEventHandler TransactionUpdate;
168
169                 #endregion
170
171                 #region Abstract Methods
172
173                 public abstract void Describe();
174                 public abstract void DescribeParameters();
175                 public abstract void Prepare(string commandText);
176                 public abstract void Execute();
177                 public abstract DbValue[] Fetch();
178                 public abstract DbValue[] GetOuputParameters();
179                 public abstract byte[] GetSqlInfo(byte[] items, int bufferLength);
180
181                 public abstract BlobBase CreateBlob();
182                 public abstract BlobBase CreateBlob(long handle);
183
184                 public abstract ArrayBase CreateArray(ArrayDesc descriptor);
185                 public abstract ArrayBase CreateArray(string tableName, string fieldName);
186                 public abstract ArrayBase CreateArray(long handle, string tableName, string fieldName);
187
188                 #endregion
189
190                 #region Finalizer
191
192                 ~StatementBase()
193                 {
194                         this.Dispose(false);
195                 }
196
197                 #endregion
198
199                 #region IDisposable     methods
200
201                 public void Dispose()
202                 {
203                         this.Dispose(true);
204                         GC.SuppressFinalize(this);
205                 }
206
207                 protected virtual void Dispose(bool disposing)
208                 {
209                         lock (this)
210                         {
211                                 if (!this.disposed)
212                                 {
213                                         this.disposed = true;
214                                 }
215                         }
216                 }
217
218                 #endregion
219
220                 #region Protected Abstract Methods
221
222                 protected abstract void TransactionUpdated(object sender, EventArgs e);
223                 protected abstract void Free(int option);
224
225                 #endregion
226
227                 #region Methods
228
229                 public string GetExecutionPlan()
230                 {
231                         string  plan            = String.Empty;
232                         int             count           = 0;
233                         int             bufferSize      = IscCodes.MAX_BUFFER_SIZE;
234                         byte[]  buffer          = this.GetSqlInfo(DescribePlanInfoItems, bufferSize);
235
236                         while (buffer[0] == IscCodes.isc_info_truncated && count < 4)
237                         {
238                                 bufferSize *= 2;
239                                 buffer = this.GetSqlInfo(DescribePlanInfoItems, bufferSize);
240                                 count++;
241                         }
242
243                         if (count > 3)
244                         {
245                                 return null;
246                         }
247
248                         int len = buffer[1];
249                         len += buffer[2] << 8;
250
251                         if (len > 0)
252                         {
253                                 plan = this.DB.Charset.GetString(buffer, 4, --len);
254                         }
255
256                         return plan;
257                 }
258
259                 public virtual void Close()
260                 {
261                         if (this.State == StatementState.Executed ||
262                                 this.State == StatementState.Error)
263                         {
264                                 if (this.StatementType == DbStatementType.Select ||
265                                         this.StatementType == DbStatementType.SelectForUpdate ||
266                                         this.StatementType == DbStatementType.StoredProcedure)
267                                 {
268                                         this.Free(IscCodes.DSQL_close);
269                                         this.ClearArrayHandles();
270                                         this.State = StatementState.Closed;
271                                 }
272                         }
273                 }
274
275                 public virtual void Release()
276                 {
277                         if (this.Transaction != null &&
278                                 this.TransactionUpdate != null)
279                         {
280                                 this.Transaction.Update -= this.TransactionUpdate;
281                                 this.TransactionUpdate = null;
282                         }
283
284                         this.Free(IscCodes.DSQL_drop);
285
286                         this.State = StatementState.Deallocated;
287                         this.StatementType = DbStatementType.None;
288                 }
289
290                 #endregion
291
292                 #region Protected Methods
293
294                 protected byte[] GetSqlInfo(byte[] items)
295                 {
296                         return this.GetSqlInfo(items, IscCodes.MAX_BUFFER_SIZE);
297                 }
298
299                 protected int GetRecordsAffected()
300                 {
301                         byte[] buffer = this.GetSqlInfo(RecordsAffectedInfoItems, IscCodes.ROWS_AFFECTED_BUFFER_SIZE);
302
303                         return this.ProcessRecordsAffectedBuffer(buffer);
304                 }
305
306                 protected int ProcessRecordsAffectedBuffer(byte[] buffer)
307                 {
308                         int insertCount = 0;
309                         int updateCount = 0;
310                         int deleteCount = 0;
311                         int selectCount = 0;
312                         int pos                 = 0;
313                         int length              = 0;
314                         int type                = 0;
315
316                         while ((type = buffer[pos++]) != IscCodes.isc_info_end)
317                         {
318                                 length = IscHelper.VaxInteger(buffer, pos, 2);
319                                 pos += 2;
320                                 switch (type)
321                                 {
322                                         case IscCodes.isc_info_sql_records:
323                                                 int l;
324                                                 int t;
325                                                 while ((t = buffer[pos++]) != IscCodes.isc_info_end)
326                                                 {
327                                                         l = IscHelper.VaxInteger(buffer, pos, 2);
328                                                         pos += 2;
329                                                         switch (t)
330                                                         {
331                                                                 case IscCodes.isc_info_req_insert_count:
332                                                                         insertCount = IscHelper.VaxInteger(
333                                                                                 buffer, pos, l);
334                                                                         break;
335
336                                                                 case IscCodes.isc_info_req_update_count:
337                                                                         updateCount = IscHelper.VaxInteger(
338                                                                                 buffer, pos, l);
339                                                                         break;
340
341                                                                 case IscCodes.isc_info_req_delete_count:
342                                                                         deleteCount = IscHelper.VaxInteger(
343                                                                                 buffer, pos, l);
344                                                                         break;
345
346                                                                 case IscCodes.isc_info_req_select_count:
347                                                                         selectCount = IscHelper.VaxInteger(
348                                                                                 buffer, pos, l);
349                                                                         break;
350                                                         }
351                                                         pos += l;
352                                                 }
353                                                 break;
354
355                                         default:
356                                                 pos += length;
357                                                 break;
358                                 }
359                         }
360
361                         return insertCount + updateCount + deleteCount;
362                 }
363
364                 protected DbStatementType GetStatementType()
365                 {
366                         byte[] buffer = this.GetSqlInfo(StatementTypeInfoItems, IscCodes.STATEMENT_TYPE_BUFFER_SIZE);
367
368                         return this.ParseStatementTypeInfo(buffer);
369                 }
370
371                 protected DbStatementType ParseStatementTypeInfo(byte[] buffer)
372                 {
373                         DbStatementType stmtType = DbStatementType.None;
374                         int pos = 0;
375                         int length = 0;
376                         int type = 0;
377
378                         while ((type = buffer[pos++]) != IscCodes.isc_info_end)
379                         {
380                                 length = IscHelper.VaxInteger(buffer, pos, 2);
381                                 pos += 2;
382                                 switch (type)
383                                 {
384                                         case IscCodes.isc_info_sql_stmt_type:
385                                                 stmtType = (DbStatementType)IscHelper.VaxInteger(buffer, pos, length);
386                                                 pos += length;
387                                                 break;
388
389                                         default:
390                                                 pos += length;
391                                                 break;
392                                 }
393                         }
394
395                         return stmtType;
396                 }
397
398                 protected void ClearArrayHandles()
399                 {
400                         if (this.Fields != null && this.Fields.Count > 0)
401                         {
402                                 for (int i = 0; i < this.Fields.Count; i++)
403                                 {
404                                         if (this.Fields[i].IsArray())
405                                         {
406                                                 this.Fields[i].ArrayHandle = null;
407                                         }
408                                 }
409                         }
410                 }
411
412                 #endregion
413         }
414 }