BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / IBM.Data.DB2 / IBM.Data.DB2 / DB2DataReader.cs
1 \r
2 //\r
3 // Permission is hereby granted, free of charge, to any person obtaining\r
4 // a copy of this software and associated documentation files (the\r
5 // "Software"), to deal in the Software without restriction, including\r
6 // without limitation the rights to use, copy, modify, merge, publish,\r
7 // distribute, sublicense, and/or sell copies of the Software, and to\r
8 // permit persons to whom the Software is furnished to do so, subject to\r
9 // the following conditions:\r
10 // \r
11 // The above copyright notice and this permission notice shall be\r
12 // included in all copies or substantial portions of the Software.\r
13 // \r
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21 //\r
22 using System;\r
23 using System.Collections;\r
24 using System.Data;\r
25 using System.Runtime.InteropServices;\r
26 using System.Globalization;\r
27 using System.Text;\r
28 \r
29 namespace IBM.Data.DB2\r
30 {\r
31         /// <summary>\r
32         /// Summary description for DB2ClientDataReader.\r
33         /// DB2ClientDataReader. \r
34         /// </summary>\r
35         public sealed class DB2DataReader : MarshalByRefObject, IDataReader\r
36         {\r
37                 private struct ColumnInfo\r
38                 {\r
39                         public string   Colname;\r
40                         public int              Sqltype;\r
41                 }\r
42 \r
43                 private object[] _resultSet;\r
44                 private ColumnInfo[] columnInfo;\r
45                 private Hashtable columnsNames;\r
46                 private const int internalBufferSize = 100;\r
47                 private IntPtr internalBuffer;\r
48                 internal DB2Connection db2Conn; \r
49                 internal DB2Command db2Comm; \r
50                 internal IntPtr hwndStmt;\r
51                 private int recordsAffected;\r
52                 private bool hasData = false;\r
53                 private int fieldCount = -1;\r
54                 private CommandBehavior behavior;\r
55                 private bool hasRows;\r
56                 private bool skipReadOnce;\r
57         \r
58                 \r
59                 #region Constructors and destructors\r
60                 /// <summary>\r
61                 /// \r
62                 /// </summary>\r
63                 /// <param name="con"></Connection object to Db2>\r
64                 /// <param name="com"></Command object>\r
65                 internal DB2DataReader(DB2Connection con, DB2Command com, CommandBehavior behavior)\r
66                 {\r
67                         db2Conn = con;\r
68                         db2Comm = com;\r
69                         this.behavior = behavior;\r
70                         hwndStmt = com.statementHandle;    //We have access to the results through the statement handle\r
71                         \r
72                         _resultSet = null;\r
73                         \r
74                         GetFieldCountAndAffectedRows();\r
75                         internalBuffer = Marshal.AllocHGlobal(internalBufferSize);\r
76 \r
77                         isClosed = false;\r
78                 }\r
79 \r
80                 #endregion\r
81 \r
82                 private void GetFieldCountAndAffectedRows()\r
83                 {\r
84                         short sqlRet;\r
85                         recordsAffected = -1;\r
86                         if((behavior & CommandBehavior.SchemaOnly) == 0)\r
87                         {\r
88                                 //How many rows affected.  numRows will be -1 if we aren't dealing with an Insert, Delete or Update, or if the statement did not execute successfully\r
89                                 sqlRet = DB2CLIWrapper.SQLRowCount(hwndStmt, out recordsAffected);\r
90                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "SQLExecDirect error.", db2Conn);\r
91                         }                       \r
92                         short colCount;\r
93                         sqlRet = DB2CLIWrapper.SQLNumResultCols(hwndStmt, out colCount);\r
94                         DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "DB2ClientDataReader - SQLNumResultCols", db2Conn);\r
95                         fieldCount = colCount;\r
96                 }\r
97 \r
98                 #region Properties\r
99 \r
100                 #region Depth property \r
101                 ///\r
102                 ///Depth of nesting for the current row, need to figure out what this translates into \r
103                 ///with DB2.\r
104                 ///\r
105                 private int depth = 0;\r
106                 public int Depth\r
107                 {\r
108                         get\r
109                         {\r
110                                 if(isClosed)\r
111                                 {\r
112                                         throw new InvalidOperationException("Reader is closed");\r
113                                 }\r
114                                 return depth;\r
115                         }\r
116                 }\r
117                 #endregion\r
118 \r
119                 #region IsClosed property\r
120                 /// <summary>\r
121                 /// True if the reader is closed.\r
122                 /// </summary>\r
123                 private bool isClosed = true;\r
124                 public bool IsClosed\r
125                 {\r
126                         get\r
127                         {\r
128                                 return isClosed;\r
129                         }\r
130                 }\r
131                 #endregion\r
132 \r
133                 #region RecordsAffected property\r
134                 ///\r
135                 /// Number of records affected by this operation.  Will be zero until we close the \r
136                 /// reader\r
137                 /// \r
138                 \r
139                 public int RecordsAffected\r
140                 {\r
141                         get\r
142                         {\r
143                                 return recordsAffected;\r
144                         }\r
145                 }\r
146                 #endregion\r
147 \r
148                 #endregion\r
149 \r
150                 #region Methods\r
151 \r
152 \r
153 \r
154                 #region Close method\r
155 \r
156                 public void Close()\r
157                 {\r
158                         Dispose();\r
159                 }\r
160 \r
161                 public void Dispose()\r
162                 {\r
163                         Dispose(true);\r
164                         GC.SuppressFinalize(this);\r
165                 }\r
166 \r
167                 void Dispose(bool disposing)\r
168                 {\r
169                         if(!isClosed) \r
170                         {\r
171                                 if(disposing)\r
172                                 {\r
173                                         short sqlRet;\r
174                                         do\r
175                                         {\r
176                                                 sqlRet = DB2CLIWrapper.SQLMoreResults(this.hwndStmt);\r
177                                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "Db2ClientDataReader - SQLMoreResults", db2Conn);\r
178                                         } while(sqlRet != DB2Constants.SQL_NO_DATA_FOUND);\r
179 \r
180                                         _resultSet = null;\r
181                                         hasData = false;\r
182                                         isClosed=true;\r
183 \r
184                                         if(db2Comm != null)\r
185                                         {\r
186                                                 db2Comm.DataReaderClosed();\r
187                                                 db2Comm = null;\r
188                                         }\r
189                                 }\r
190                                 Marshal.FreeHGlobal(internalBuffer);\r
191                         }\r
192                         isClosed = true;\r
193                 }\r
194 \r
195                 ~DB2DataReader()\r
196                 {\r
197                         Dispose(false);\r
198                 }\r
199 \r
200                 #endregion\r
201 \r
202                 #region GetSchemaTable \r
203 \r
204                 public DataTable GetSchemaTable()\r
205                 {\r
206                         if(isClosed)\r
207                         {\r
208                                 throw new InvalidOperationException("No data exists for the row/column.");\r
209                         }\r
210 \r
211                         DataTable _schemaTable = BuildNewSchemaTable();\r
212                         \r
213                         short sqlRet;\r
214                         IntPtr ptrCharacterAttribute = IntPtr.Zero;\r
215                         InitMem(256, ref ptrCharacterAttribute);\r
216                         short buflen = 256;\r
217                         short strlen = 256;\r
218                         int numericattr = 0;\r
219                         int colsize;\r
220                         string colname;\r
221                         int sqltype;\r
222                         int precision;\r
223                         int scale;\r
224                         int nullable;\r
225                         int updatable;\r
226                         int isautoincrement;\r
227                         string baseschemaname;\r
228                         //string basecatalogname;\r
229                         string basetablename;\r
230                         string basecolumnname;\r
231 \r
232                         string previousTableName = null;\r
233                         string previousSchemaName = null;\r
234                         bool differentTablesUsed = false;\r
235 \r
236                         for (short i=1; i<=fieldCount; i++) \r
237                         {\r
238                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_COLUMN_NAME, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
239                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
240                                 colname = Marshal.PtrToStringUni(ptrCharacterAttribute);\r
241                                 \r
242                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_CONCISE_TYPE, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
243                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
244                                 sqltype = numericattr;\r
245                                 \r
246                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_OCTET_LENGTH, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
247                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
248                                 colsize = numericattr;\r
249                                 \r
250                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_PRECISION, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
251                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
252                                 precision = numericattr;\r
253                                 \r
254                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_SCALE, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
255                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
256                                 scale = numericattr;\r
257 \r
258                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_NULLABLE, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
259                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
260                                 nullable = numericattr;\r
261 \r
262                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_UPDATABLE, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
263                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
264                                 updatable = numericattr;\r
265                                 \r
266                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_AUTO_UNIQUE_VALUE, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
267                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
268                                 isautoincrement = numericattr;\r
269                                 \r
270                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_BASE_COLUMN_NAME, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
271                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
272                                 basecolumnname = Marshal.PtrToStringUni(ptrCharacterAttribute);\r
273 \r
274                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_BASE_TABLE_NAME, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
275                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
276                                 basetablename = Marshal.PtrToStringUni(ptrCharacterAttribute);\r
277                                 \r
278                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)i, (short)DB2Constants.SQL_DESC_SCHEMA_NAME, ptrCharacterAttribute, buflen, ref strlen, ref numericattr);\r
279                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable", db2Conn);\r
280                                 baseschemaname = Marshal.PtrToStringUni(ptrCharacterAttribute);\r
281                                 DataRow r = _schemaTable.NewRow();\r
282                                 \r
283                                 r["ColumnName"] = colname;\r
284                                 r["ColumnOrdinal"] = i - 1;\r
285                                 r["ColumnSize"] = colsize;\r
286                                 r["NumericPrecision"] = precision;\r
287                                 r["NumericScale"] = scale;\r
288                                 r["DataType"] = GetManagedType((short)sqltype);\r
289                                 r["ProviderType"] = sqltype;\r
290                                 r["IsLong"] = IsLong((short)sqltype);\r
291                                 r["AllowDBNull"] = (nullable==0) ? false : true;\r
292                                 r["IsReadOnly"] = (basecolumnname == null) || (basecolumnname == "");\r
293                                 r["IsRowVersion"] = false;\r
294                                 r["IsUnique"] = false;\r
295                                 r["IsKeyColumn"] = false;\r
296                                 r["IsAutoIncrement"] = (isautoincrement==0) ? false : true;\r
297                                 r["BaseSchemaName"] = baseschemaname;\r
298                                 r["BaseCatalogName"] = "";\r
299                                 r["BaseTableName"] = basetablename;\r
300                                 r["BaseColumnName"] = basecolumnname;\r
301                                 \r
302                                 _schemaTable.Rows.Add(r);\r
303 \r
304                                 if(!differentTablesUsed)\r
305                                 {\r
306                                         if(((previousSchemaName == baseschemaname) && (previousTableName == basetablename)) || \r
307                                                 (previousTableName == null))\r
308                                         {\r
309                                                 previousTableName = basetablename;\r
310                                                 previousSchemaName = baseschemaname;\r
311                                         }\r
312                                         else\r
313                                         {\r
314                                                 differentTablesUsed = true;\r
315                                         }\r
316                                 }\r
317                         }\r
318                         if(!differentTablesUsed && \r
319                                 ((behavior & CommandBehavior.KeyInfo) != 0) &&\r
320                                 (db2Comm.Transaction == null) &&\r
321                                 (previousTableName != null) &&\r
322                                 (previousTableName != ""))\r
323                         {\r
324                                 DB2Command schemaInfoCommand = db2Conn.CreateCommand();\r
325                                 schemaInfoCommand.CommandText = \r
326                                         "select concat(concat(INDSCHEMA,'.'),INDNAME), COLNAMES, UNIQUERULE from syscat.INDEXES " +\r
327                                         "where TABSCHEMA=? and TABNAME=? and uniquerule in ('P','U') order by UNIQUERULE";\r
328                                 schemaInfoCommand.Parameters.Add("TABSCHEMA", previousSchemaName);\r
329                                 schemaInfoCommand.Parameters.Add("TABNAME", previousTableName);\r
330                                 using(DB2DataReader reader = schemaInfoCommand.ExecuteReader())\r
331                                 {\r
332                                         bool keyColumnSet = false;\r
333                                         while(reader.Read())\r
334                                         {\r
335                                                 string indexName = reader.GetString(0);\r
336                                                 string[] indexColumns = reader.GetString(1).TrimStart('-', '+').Split('-', '+');\r
337                                                 bool primary = reader.GetString(2) == "P";\r
338 \r
339                                                 bool allColumnsFound = true;\r
340                                                 for(int i= 0; i < indexColumns.Length; i++)\r
341                                                 {\r
342                                                         int ordinal = FieldNameLookup(_schemaTable, indexColumns[i]);\r
343                                                         if(ordinal < 0)\r
344                                                         {\r
345                                                                 allColumnsFound = false;\r
346                                                                 break;\r
347                                                         }\r
348                                                         if(indexColumns.Length == 1)\r
349                                                                 _schemaTable.Rows[ordinal]["IsUnique"] = true;\r
350                                                 }\r
351                                                 if(allColumnsFound && !keyColumnSet)\r
352                                                 {\r
353                                                         for(int i= 0; i < indexColumns.Length; i++)\r
354                                                                 _schemaTable.Rows[FieldNameLookup(_schemaTable, indexColumns[i])]["IsKeyColumn"] = true;\r
355                                                         keyColumnSet = true;\r
356                                                 }\r
357                                         }\r
358                                 }\r
359                                 if(db2Conn.openConnection.MajorVersion >= 8)\r
360                                 {\r
361                                         try\r
362                                         {\r
363                                                 schemaInfoCommand.CommandText = \r
364                                                         "select COLNAME from SYSCAT.COLIDENTATTRIBUTES where TABSCHEMA=? and TABNAME=?";\r
365                                                 using(DB2DataReader reader = schemaInfoCommand.ExecuteReader())\r
366                                                 {\r
367                                                         while(reader.Read())\r
368                                                         {\r
369                                                                 string columnName = reader.GetString(0);\r
370 \r
371                                                                 int ordinal = FieldNameLookup(_schemaTable, columnName);\r
372                                                                 if(ordinal >= 0)\r
373                                                                         _schemaTable.Rows[ordinal]["IsAutoIncrement"] = true;\r
374                                                         }\r
375                                                 }\r
376                                         }\r
377                                         catch{}\r
378                                 }\r
379                         }\r
380                         return _schemaTable;\r
381                 }\r
382                 #endregion\r
383 \r
384                 #region NextResult \r
385 \r
386                 public bool NextResult()\r
387                 {\r
388                         hasRows = false;\r
389                         skipReadOnce = false;\r
390                         hasData = false;\r
391                         columnInfo = null;\r
392                         _resultSet = null;\r
393                 \r
394                         if((behavior & (CommandBehavior.SchemaOnly | CommandBehavior.SingleResult)) != 0)\r
395                                 return false;\r
396 \r
397                         short sqlRet = DB2CLIWrapper.SQLMoreResults(this.hwndStmt);\r
398                         if(sqlRet == DB2Constants.SQL_NO_DATA_FOUND) \r
399                                 return false;\r
400                         DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "Db2ClientDataReader - SQLMoreResults", db2Conn);\r
401                         return true;\r
402                 }\r
403                 #endregion\r
404 \r
405                 #region Read\r
406 \r
407 #if !NET_1_0\r
408                 public bool HasRows\r
409                 {\r
410                         get\r
411                         {\r
412                                 if(hasData)\r
413                                         return true;\r
414 \r
415                                 hasRows = Read();\r
416                                 hasData = false;\r
417                                 skipReadOnce = true;\r
418                                 return hasRows;\r
419                         }\r
420                 }\r
421 #endif\r
422 \r
423                 public bool Read()\r
424                 {\r
425                         if (isClosed)\r
426                                 throw new InvalidOperationException("Reader is closed");\r
427                         if((behavior & CommandBehavior.SchemaOnly) != 0)\r
428                                 return false;\r
429 \r
430                         if(skipReadOnce)\r
431                         {\r
432                                 skipReadOnce = false;\r
433                                 hasData = hasRows;\r
434                                 return hasRows;\r
435                         }\r
436 \r
437                         _resultSet = null;\r
438                         hasData = false;\r
439 \r
440                         short sqlRet = DB2CLIWrapper.SQLFetch(hwndStmt);\r
441                         if(sqlRet == DB2Constants.SQL_NO_DATA_FOUND)\r
442                                 return false;\r
443                         DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "DB2ClientDataReader - SQLFetch 1", db2Conn);\r
444 \r
445                         hasData = true;\r
446                         return true;\r
447                 }\r
448                 #endregion\r
449 \r
450                 #region GetColumnInfo\r
451                 private void GetColumnInfo()\r
452                 {\r
453                         if(isClosed)\r
454                                 throw new InvalidOperationException("Reader is closed");\r
455                         if(fieldCount <= 0)\r
456                                 throw new InvalidOperationException("No Fields found"); // TODO: check error\r
457                         if(columnInfo != null)\r
458                                 return;\r
459                 \r
460                         columnInfo = new ColumnInfo[fieldCount];\r
461                         columnsNames = new Hashtable(fieldCount);\r
462                         \r
463                         StringBuilder sb = new StringBuilder(400);\r
464                         for(int i = 0; i < columnInfo.Length; i++)\r
465                         {\r
466                                 short sqlRet;\r
467                                 short strlen;\r
468                                 int numericAttribute;\r
469 \r
470                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)(i + 1), (short)DB2Constants.SQL_DESC_BASE_COLUMN_NAME, sb, (short)sb.Capacity, out strlen, out numericAttribute);\r
471                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable");\r
472                                 columnInfo[i].Colname = sb.ToString();\r
473                                 columnsNames[columnInfo[i].Colname.ToUpper()] = i;\r
474 \r
475                                 sqlRet = DB2CLIWrapper.SQLColAttribute(hwndStmt, (short)(i + 1), (short)DB2Constants.SQL_DESC_CONCISE_TYPE, sb, (short)sb.Capacity, out strlen, out columnInfo[i].Sqltype);\r
476                                 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "GetSchemaTable");\r
477 \r
478 \r
479                         }\r
480                 }\r
481                 #endregion\r
482 \r
483                 #region Describe/Bind/Fetch functions\r
484                 ///\r
485                 ///Broke these out so that we can use different paths for Immediate executions and Prepared executions\r
486                 /// <summary>\r
487                 /// Does the describe and bind steps for the query result set.  Called for both immediate and prepared queries. \r
488                 /// </summary>\r
489                 \r
490 /// <summary>\r
491 /// FetchResults does  what it says.\r
492 /// </summary>\r
493 /// <param name="dbVals"></param>\r
494 /// <param name="sqlLen_or_IndPtr"></param>\r
495 /// <param name="_resultSet"></param>\r
496                 private int FieldNameLookup(DataTable _schemaTable, string name)\r
497                 {\r
498                         for(int i = 0; i < _schemaTable.Rows.Count; i++)\r
499                         {\r
500                                 if(CultureInfo.CurrentCulture.CompareInfo.Compare(name, (string)_schemaTable.Rows[i]["BaseColumnName"],\r
501                                         CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase) == 0)\r
502                                 {\r
503                                         return i;\r
504                                 }\r
505                         }\r
506                         return -1;\r
507                 }\r
508                 \r
509                 #endregion\r
510 \r
511                 #region IDataRecord Interface\r
512                 ///Code for the IDataRecord interface\r
513                 ///\r
514                 #region FieldCount\r
515                 ///\r
516                 ///\r
517                 public int FieldCount\r
518                 {\r
519                         get\r
520                         {\r
521                                 if (isClosed)\r
522                                         throw new InvalidOperationException("Reader is closed");\r
523 \r
524                                 return fieldCount;\r
525                         }\r
526                 }\r
527                 #endregion\r
528 \r
529                 #region Item accessors\r
530                 public object this[string name]\r
531                 {\r
532                         get\r
533                         {\r
534                                 int ordinal = GetOrdinal(name);\r
535                                 return this[ordinal];\r
536                         }\r
537                 }\r
538                 public object this[int col]\r
539                 {\r
540                         get\r
541                         {\r
542                                 if(columnInfo == null)\r
543                                 {\r
544                                         GetColumnInfo();\r
545                                 }\r
546                                 switch(columnInfo[col].Sqltype)\r
547                                 {\r
548                                         case DB2Constants.SQL_INTEGER:\r
549                                                 return GetInt32Internal(col);\r
550                                         case DB2Constants.SQL_SMALLINT:\r
551                                                 return GetInt16Internal(col);\r
552                                         case DB2Constants.SQL_BIGINT:\r
553                                                 return GetInt64Internal(col);\r
554                                         case DB2Constants.SQL_DOUBLE:\r
555                                                 return GetDoubleInternal(col);\r
556                                         case DB2Constants.SQL_REAL:\r
557                                                 return GetFloatInternal(col);\r
558                                         case DB2Constants.SQL_DECIMAL:\r
559                                                 return GetDecimalInternal(col);\r
560                                         case DB2Constants.SQL_DATETIME:\r
561                                         case DB2Constants.SQL_TYPE_TIMESTAMP:\r
562                                                 return GetDateTimeInternal(col);\r
563                                         case DB2Constants.SQL_TYPE_DATE:\r
564                                                 return GetDateInternal(col);\r
565                                         case DB2Constants.SQL_TYPE_TIME:\r
566                                                 return GetTimeInternal(col);\r
567                                         case DB2Constants.SQL_TYPE_CLOB:\r
568                                         case DB2Constants.SQL_CHAR:\r
569                                         case DB2Constants.SQL_VARCHAR:\r
570                                                 return GetStringInternal(col);\r
571                                         case DB2Constants.SQL_TYPE_BLOB:\r
572                                         case DB2Constants.SQL_TYPE_BINARY:\r
573                                         case DB2Constants.SQL_LONGVARBINARY:\r
574                                         case DB2Constants.SQL_VARBINARY:\r
575                                                 return GetBlobDataInternal(col);\r
576                                 }\r
577                                 throw new NotImplementedException("Unknown SQL type " + columnInfo[col].Sqltype);\r
578                         }\r
579                 }\r
580                 #endregion\r
581 \r
582                 #region GetBytes\r
583                 ///\r
584                 ///  GetBytes, return a stream of bytes\r
585                 ///\r
586                 public long GetBytes(int col, long fieldOffset, byte[] buffer, int bufferOffset, int length)\r
587                 {\r
588                         // TODO: need better implementation for big BLOBs\r
589 \r
590                         byte[] sourceArray = (byte[])this[col];\r
591 #if NET_1_0\r
592                         if(buffer == null)\r
593                         {\r
594                                 Array.Copy(sourceArray, (int)fieldOffset, buffer, bufferOffset, length);\r
595                         }\r
596                         return sourceArray.Length;\r
597 #else\r
598                         if(buffer == null)\r
599                         {\r
600                                 Array.Copy(sourceArray, fieldOffset, buffer, bufferOffset, length);\r
601                         }\r
602                         return sourceArray.LongLength;\r
603 #endif\r
604                 }\r
605                 #endregion\r
606 \r
607                 #region GetChars\r
608                 ///\r
609                 ///GetChars, returns char array\r
610                 ///\r
611                 public long GetChars(int col, long fieldOffset, char[] buffer, int bufferOffset, int length)\r
612                 {\r
613                         // TODO: need better implementation for big CLOBs\r
614 \r
615                         string sourceString = GetString(col);\r
616                         if(buffer == null)\r
617                         {\r
618                                 sourceString.CopyTo((int)fieldOffset, buffer, bufferOffset, length);\r
619                         }\r
620                         return (long)sourceString.Length;\r
621                 }\r
622                 #endregion\r
623 \r
624                 #region GetBoolean method\r
625 \r
626                 public Boolean GetBoolean(int col)\r
627                 {\r
628                         return (Boolean)GetBooleanInternal(col);\r
629                 }\r
630                 internal object GetBooleanInternal(int col)\r
631                 {\r
632                         if((col < 0) || (col >= fieldCount))\r
633                         {\r
634                                 throw new IndexOutOfRangeException("col");\r
635                         }\r
636                         if(!hasData)\r
637                         {\r
638                                 throw new InvalidOperationException("No data");\r
639                         }\r
640                         if(_resultSet == null)\r
641                         {\r
642                                 _resultSet = new object[fieldCount];\r
643                         }\r
644                         if(_resultSet[col] == null)\r
645                         {\r
646                                 int len;\r
647                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_BIT, internalBuffer, internalBufferSize, out len);\r
648                                 if(len == DB2Constants.SQL_NULL_DATA)\r
649                                 {\r
650                                         _resultSet[col] = DBNull.Value;\r
651                                 }\r
652                                 else\r
653                                 {\r
654                                         _resultSet[col] = Marshal.ReadByte(internalBuffer) != 0;\r
655                                 }\r
656                         }               \r
657                         return _resultSet[col];\r
658                 }\r
659                 #endregion\r
660 \r
661                 #region GetGuid\r
662                 ///\r
663                 /// GetDateTime method\r
664                 /// \r
665                 public Guid GetGuid(int col)\r
666                 {\r
667                         return (Guid)GetGuidInternal(col);\r
668                 }\r
669                 internal object GetGuidInternal(int col)\r
670                 {\r
671                         if((col < 0) || (col >= fieldCount))\r
672                         {\r
673                                 throw new IndexOutOfRangeException("col");\r
674                         }\r
675                         if(!hasData)\r
676                         {\r
677                                 throw new InvalidOperationException("No data");\r
678                         }\r
679                         if(_resultSet == null)\r
680                         {\r
681                                 _resultSet = new object[fieldCount];\r
682                         }\r
683                         if(_resultSet[col] == null)\r
684                         {\r
685                                 int len;\r
686                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_GUID, internalBuffer, internalBufferSize, out len);\r
687                                 if(len == DB2Constants.SQL_NULL_DATA)\r
688                                 {\r
689                                         _resultSet[col] = DBNull.Value;\r
690                                 }\r
691                                 else\r
692                                 {\r
693                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(Guid)); \r
694                                 }\r
695                         }               \r
696                         return _resultSet[col];\r
697                 }\r
698 \r
699                 #endregion\r
700 \r
701                 #region GetByte\r
702                 ///\r
703                 ///GetByte\r
704                 ///\r
705                 public Byte GetByte(int col)\r
706                 {\r
707                         return (Byte)GetByteInternal(col);\r
708                 }\r
709                 internal object GetByteInternal(int col)\r
710                 {\r
711                         if((col < 0) || (col >= fieldCount))\r
712                         {\r
713                                 throw new IndexOutOfRangeException("col");\r
714                         }\r
715                         if(!hasData)\r
716                         {\r
717                                 throw new InvalidOperationException("No data");\r
718                         }\r
719                         if(_resultSet == null)\r
720                         {\r
721                                 _resultSet = new object[fieldCount];\r
722                         }\r
723                         if(_resultSet[col] == null)\r
724                         {\r
725                                 int len;\r
726                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_UTINYINT, internalBuffer, 10, out len);\r
727                                 if(len == DB2Constants.SQL_NULL_DATA)\r
728                                 {\r
729                                         _resultSet[col] = DBNull.Value;\r
730                                 }\r
731                                 else\r
732                                 {\r
733                                         _resultSet[col] = Marshal.ReadByte(internalBuffer);\r
734                                 }\r
735                         }               \r
736                         return _resultSet[col];\r
737                 }\r
738                 #endregion\r
739 \r
740                 #region GetChar\r
741                 ///\r
742                 ///GetChar, return column as a char\r
743                 ///\r
744                 public Char GetChar(int col)\r
745                 {\r
746                         return (Char)GetCharInternal(col);\r
747                 }\r
748                 internal object GetCharInternal(int col)\r
749                 {\r
750                         if((col < 0) || (col >= fieldCount))\r
751                         {\r
752                                 throw new IndexOutOfRangeException("col");\r
753                         }\r
754                         if(!hasData)\r
755                         {\r
756                                 throw new InvalidOperationException("No data");\r
757                         }\r
758                         if(_resultSet == null)\r
759                         {\r
760                                 _resultSet = new object[fieldCount];\r
761                         }\r
762                         if(_resultSet[col] == null)\r
763                         {\r
764                                 int len;\r
765                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_WCHAR, internalBuffer, 10, out len);\r
766                                 if(len == DB2Constants.SQL_NULL_DATA)\r
767                                 {\r
768                                         _resultSet[col] = DBNull.Value;\r
769                                 }\r
770                                 else\r
771                                 {\r
772                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(char));\r
773                                 }\r
774                         }               \r
775                         return _resultSet[col];\r
776                 }\r
777                 #endregion\r
778 \r
779                 #region GetData\r
780                 ///\r
781                 /// GetData method\r
782                 /// \r
783                 public IDataReader GetData(int col)\r
784                 {\r
785                         //Have to research this one, not quite sure what the docs mean\r
786                         //DB2 does have some structured data types, is that what this is for?\r
787                         throw new NotSupportedException();\r
788                 }\r
789                 #endregion\r
790 \r
791                 #region GetDataTypeName\r
792                 ///\r
793                 ///GetDataTypeName return the type of data\r
794                 ///\r
795                 public string GetDataTypeName(int col)\r
796                 {\r
797                         if(columnInfo == null)\r
798                         {\r
799                                 GetColumnInfo();\r
800                         }\r
801                         switch(columnInfo[col].Sqltype)\r
802                         {\r
803                                 case DB2Constants.SQL_INTEGER:\r
804                                         return "INTEGER";\r
805                                 case DB2Constants.SQL_SMALLINT:\r
806                                         return "SMALLINT";\r
807                                 case DB2Constants.SQL_BIGINT:\r
808                                         return "BIGINT";\r
809                                 case DB2Constants.SQL_DOUBLE:\r
810                                         return "DOUBLE";\r
811                                 case DB2Constants.SQL_REAL:\r
812                                         return "REAL";\r
813                                 case DB2Constants.SQL_DECIMAL:\r
814                                         return "DECIMAL";\r
815                                 case DB2Constants.SQL_DATETIME:\r
816                                         return "DATETIME";\r
817                                 case DB2Constants.SQL_TYPE_TIMESTAMP:\r
818                                         return "TIMESTAMP";\r
819                                 case DB2Constants.SQL_TYPE_DATE:\r
820                                         return "DATE";\r
821                                 case DB2Constants.SQL_TYPE_TIME:\r
822                                         return "TIME";\r
823                                 case DB2Constants.SQL_TYPE_CLOB:\r
824                                         return "CLOB";\r
825                                 case DB2Constants.SQL_CHAR:\r
826                                         return "CHAR";\r
827                                 case DB2Constants.SQL_VARCHAR:\r
828                                         return "VARCHAR";\r
829                                 case DB2Constants.SQL_TYPE_BLOB:\r
830                                         return "BLOB";\r
831                                 case DB2Constants.SQL_TYPE_BINARY:\r
832                                         return "BINARY";\r
833                                 case DB2Constants.SQL_LONGVARBINARY:\r
834                                         return "LONGVARBINARY";\r
835                                 case DB2Constants.SQL_VARBINARY:\r
836                                         return "VARBINARY";\r
837                         }\r
838                         throw new NotImplementedException("Unknown SQL type " + columnInfo[col].Sqltype);\r
839                 }\r
840                 #endregion\r
841 \r
842                 #region GetDateTime\r
843                 ///\r
844                 /// GetDateTime method\r
845                 /// \r
846 \r
847                 public DateTime GetDateTime(int col)\r
848                 {\r
849                         return (DateTime)GetDateTimeInternal(col);\r
850                 }\r
851                 internal object GetDateTimeInternal(int col)\r
852                 {\r
853                         if((col < 0) || (col >= fieldCount))\r
854                         {\r
855                                 throw new IndexOutOfRangeException("col");\r
856                         }\r
857                         if(!hasData)\r
858                         {\r
859                                 throw new InvalidOperationException("No data");\r
860                         }\r
861                         if(_resultSet == null)\r
862                         {\r
863                                 _resultSet = new object[fieldCount];\r
864                         }\r
865                         if(_resultSet[col] == null)\r
866                         {\r
867                                 int len;\r
868                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_TIMESTAMP, internalBuffer, internalBufferSize, out len);\r
869                                 if(len == DB2Constants.SQL_NULL_DATA)\r
870                                 {\r
871                                         _resultSet[col] = DBNull.Value;\r
872                                 }\r
873                                 else\r
874                                 {\r
875                                         DateTime ret = new DateTime(\r
876                                                 Marshal.ReadInt16(internalBuffer, 0),  // year\r
877                                                 Marshal.ReadInt16(internalBuffer, 2),  // month\r
878                                                 Marshal.ReadInt16(internalBuffer, 4),  // day\r
879                                                 Marshal.ReadInt16(internalBuffer, 6),  // hour\r
880                                                 Marshal.ReadInt16(internalBuffer, 8),  // minute\r
881                                                 Marshal.ReadInt16(internalBuffer, 10));// second\r
882                                         _resultSet[col] = ret.AddTicks(Marshal.ReadInt32(internalBuffer, 12) / 100); // nanoseconds \r
883                                 }\r
884                         }               \r
885                         return _resultSet[col];\r
886                 }\r
887                 #endregion\r
888 \r
889                 #region GetDate\r
890                 ///\r
891                 /// GetDate method\r
892                 /// \r
893                 public DateTime GetDate(int col)\r
894                 {\r
895                         return (DateTime)GetDateInternal(col);\r
896                 }\r
897                 internal object GetDateInternal(int col)\r
898                 {\r
899                         if((col < 0) || (col >= fieldCount))\r
900                         {\r
901                                 throw new IndexOutOfRangeException("col");\r
902                         }\r
903                         if(!hasData)\r
904                         {\r
905                                 throw new InvalidOperationException("No data");\r
906                         }\r
907                         if(_resultSet == null)\r
908                         {\r
909                                 _resultSet = new object[fieldCount];\r
910                         }\r
911                         if(_resultSet[col] == null)\r
912                         {\r
913                                 int len;\r
914                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_DATE, internalBuffer, internalBufferSize, out len);\r
915                                 if(len == DB2Constants.SQL_NULL_DATA)\r
916                                 {\r
917                                         _resultSet[col] = DBNull.Value;\r
918                                 }\r
919                                 else\r
920                                 {\r
921                                         _resultSet[col] = new DateTime(\r
922                                                 Marshal.ReadInt16(internalBuffer, 0),  // year\r
923                                                 Marshal.ReadInt16(internalBuffer, 2),  // month\r
924                                                 Marshal.ReadInt16(internalBuffer, 4));  // day\r
925                                 }\r
926                         }               \r
927                         return _resultSet[col];\r
928                 }\r
929 \r
930                 #endregion\r
931 \r
932                 #region GetTime\r
933                 ///\r
934                 /// GetTime method\r
935                 /// \r
936                 public TimeSpan GetTimeSpan(int col)\r
937                 {\r
938                         return (TimeSpan)GetTimeInternal(col);\r
939                 }\r
940                 public TimeSpan GetTime(int col)\r
941                 {\r
942                         return (TimeSpan)GetTimeInternal(col);\r
943                 }\r
944                 internal object GetTimeInternal(int col)\r
945                 {\r
946                         if((col < 0) || (col >= fieldCount))\r
947                         {\r
948                                 throw new IndexOutOfRangeException("col");\r
949                         }\r
950                         if(!hasData)\r
951                         {\r
952                                 throw new InvalidOperationException("No data");\r
953                         }\r
954                         if(_resultSet == null)\r
955                         {\r
956                                 _resultSet = new object[fieldCount];\r
957                         }\r
958                         if(_resultSet[col] == null)\r
959                         {\r
960                                 int len;\r
961                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_TIME, internalBuffer, internalBufferSize, out len);\r
962                                 if(len == DB2Constants.SQL_NULL_DATA)\r
963                                 {\r
964                                         _resultSet[col] = DBNull.Value;\r
965                                 }\r
966                                 else\r
967                                 {\r
968                                         _resultSet[col] = new TimeSpan(\r
969                                                 Marshal.ReadInt16(internalBuffer, 0),  // Hour\r
970                                                 Marshal.ReadInt16(internalBuffer, 2),  // Minute\r
971                                                 Marshal.ReadInt16(internalBuffer, 4)); // Second\r
972                                 }\r
973                         }               \r
974                         return _resultSet[col];\r
975                 }\r
976 \r
977                 #endregion\r
978 \r
979 \r
980                 #region GetDecimal\r
981                 ///\r
982                 ///GetDecimal method\r
983                 ///\r
984 \r
985                 public Decimal GetDecimal(int col)\r
986                 {\r
987                         return (Decimal)GetDecimalInternal(col);\r
988                 }\r
989                 internal object GetDecimalInternal(int col)\r
990                 {\r
991                         object tmp = GetStringInternal(col);\r
992                         if(tmp is string)\r
993                         {\r
994                                 _resultSet[col] = decimal.Parse(((string)_resultSet[col]).Replace(',','.'),     // sometimes we get a '.' and sometimes we get a ','\r
995                                         System.Globalization.CultureInfo.InvariantCulture);\r
996                         }\r
997                         //                      if((col < 0) || (col >= fieldCount))    // only works on windows UDB DB2 V8?\r
998                         //                      {\r
999                         //                              throw new IndexOutOfRangeException("col");\r
1000                         //                      }\r
1001                         //                      if(!hasData)\r
1002                         //                      {\r
1003                         //                              throw new InvalidOperationException("No data");\r
1004                         //                      }\r
1005                         //                      if(_resultSet == null)\r
1006                         //                      {\r
1007                         //                              _resultSet = new object[fieldCount];\r
1008                         //                      }\r
1009                         //                      if(_resultSet[col] == null)\r
1010                         //                      {\r
1011                         //                              int len;\r
1012                         //                              short sqlRet = Db2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)Db2Constants.SQL_C_DECIMAL_OLEDB, internalBuffer, internalBufferSize, out len);\r
1013                         //                              if(len == Db2Constants.SQL_NULL_DATA)\r
1014                         //                              {\r
1015                         //                                      _resultSet[col] = DBNull.Value;\r
1016                         //                              }\r
1017                         //                              else\r
1018                         //                              {\r
1019                         //                                      _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(decimal));\r
1020                         //                              }\r
1021                         //                      }               \r
1022                         return _resultSet[col];\r
1023                 }\r
1024                 #endregion\r
1025 \r
1026                 #region GetDouble \r
1027                 ///\r
1028                 /// GetDouble \r
1029                 /// \r
1030                 public Double GetDouble(int col)\r
1031                 {\r
1032                         return (Double)GetDoubleInternal(col);\r
1033                 }\r
1034                 internal object GetDoubleInternal(int col)\r
1035                 {\r
1036                         if((col < 0) || (col >= fieldCount))\r
1037                         {\r
1038                                 throw new IndexOutOfRangeException("col");\r
1039                         }\r
1040                         if(!hasData)\r
1041                         {\r
1042                                 throw new InvalidOperationException("No data");\r
1043                         }\r
1044                         if(_resultSet == null)\r
1045                         {\r
1046                                 _resultSet = new object[fieldCount];\r
1047                         }\r
1048                         if(_resultSet[col] == null)\r
1049                         {\r
1050                                 int len;\r
1051                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_DOUBLE, internalBuffer, internalBufferSize, out len);\r
1052                                 if(len == DB2Constants.SQL_NULL_DATA)\r
1053                                 {\r
1054                                         _resultSet[col] = DBNull.Value;\r
1055                                 }\r
1056                                 else\r
1057                                 {\r
1058                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(double));\r
1059                                 }\r
1060                         }               \r
1061                         return _resultSet[col];\r
1062                 }\r
1063                 #endregion\r
1064 \r
1065                 #region GetFieldType\r
1066                 ///\r
1067                 /// Type GetFieldType\r
1068                 ///\r
1069                 public Type GetFieldType(int col)\r
1070                 {\r
1071                         if(columnInfo == null)\r
1072                         {\r
1073                                 GetColumnInfo();\r
1074                         }\r
1075                         return GetManagedType(columnInfo[col].Sqltype);\r
1076                 }\r
1077                 #endregion\r
1078 \r
1079                 #region GetFloat\r
1080                 ///\r
1081                 /// GetFloat\r
1082                 /// \r
1083                 public float GetFloat(int col)\r
1084                 {\r
1085                         return (float)GetFloatInternal(col);\r
1086                 }\r
1087                 internal object GetFloatInternal(int col)\r
1088                 {\r
1089                         if((col < 0) || (col >= fieldCount))\r
1090                         {\r
1091                                 throw new IndexOutOfRangeException("col");\r
1092                         }\r
1093                         if(!hasData)\r
1094                         {\r
1095                                 throw new InvalidOperationException("No data");\r
1096                         }\r
1097                         if(_resultSet == null)\r
1098                         {\r
1099                                 _resultSet = new object[fieldCount];\r
1100                         }\r
1101                         if(_resultSet[col] == null)\r
1102                         {\r
1103                                 int len;\r
1104                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_REAL, internalBuffer, internalBufferSize, out len);\r
1105                                 if(len == DB2Constants.SQL_NULL_DATA)\r
1106                                 {\r
1107                                         _resultSet[col] = DBNull.Value;\r
1108                                 }\r
1109                                 else\r
1110                                 {\r
1111                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(float));\r
1112                                 }\r
1113                         }               \r
1114                         return _resultSet[col];\r
1115                 }\r
1116                 #endregion\r
1117 \r
1118                 #region The GetInt?? series\r
1119                 ///\r
1120                 ///GetInt16\r
1121                 ///\r
1122                 public short GetInt16(int col)\r
1123                 {\r
1124                         return (short)GetInt16Internal(col);\r
1125                 }\r
1126 \r
1127                 internal object GetInt16Internal(int col)\r
1128                 {\r
1129                         if((col < 0) || (col >= fieldCount))\r
1130                         {\r
1131                                 throw new IndexOutOfRangeException("col");\r
1132                         }\r
1133                         if(!hasData)\r
1134                         {\r
1135                                 throw new InvalidOperationException("No data");\r
1136                         }\r
1137                         if(_resultSet == null)\r
1138                         {\r
1139                                 _resultSet = new object[fieldCount];\r
1140                         }\r
1141                         if(_resultSet[col] == null)\r
1142                         {\r
1143                                 int len;\r
1144                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_SSHORT, internalBuffer, internalBufferSize, out len);\r
1145                                 if(len == DB2Constants.SQL_NULL_DATA)\r
1146                                 {\r
1147                                         _resultSet[col] = DBNull.Value;\r
1148                                 }\r
1149                                 else\r
1150                                 {\r
1151                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(short));\r
1152                                 }\r
1153                         }               \r
1154                         return _resultSet[col];\r
1155                 }\r
1156                 ///\r
1157                 ///GetInt32\r
1158                 ///\r
1159                 public int GetInt32(int col)\r
1160                 {\r
1161                         return (int)GetInt32Internal(col);\r
1162                 }\r
1163 \r
1164                 internal object GetInt32Internal(int col)\r
1165                 {\r
1166                         if((col < 0) || (col >= fieldCount))\r
1167                         {\r
1168                                 throw new IndexOutOfRangeException("col");\r
1169                         }\r
1170                         if(!hasData)\r
1171                         {\r
1172                                 throw new InvalidOperationException("No data");\r
1173                         }\r
1174                         if(_resultSet == null)\r
1175                         {\r
1176                                 _resultSet = new object[fieldCount];\r
1177                         }\r
1178                         if(_resultSet[col] == null)\r
1179                         {\r
1180                                 int len;\r
1181                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_SLONG, internalBuffer, internalBufferSize, out len);\r
1182                                 if(len == DB2Constants.SQL_NULL_DATA)\r
1183                                 {\r
1184                                         _resultSet[col] = DBNull.Value;\r
1185                                 }\r
1186                                 else\r
1187                                 {\r
1188                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(int));\r
1189                                 }\r
1190                         }               \r
1191                         return _resultSet[col];\r
1192                 }\r
1193 \r
1194                 ///\r
1195                 ///GetInt64\r
1196                 ///\r
1197                 public long GetInt64(int col)\r
1198                 {\r
1199                         return (long)GetInt64Internal(col);\r
1200                 }\r
1201 \r
1202                 internal object GetInt64Internal(int col)\r
1203                 {\r
1204                         if((col < 0) || (col >= fieldCount))\r
1205                         {\r
1206                                 throw new IndexOutOfRangeException("col");\r
1207                         }\r
1208                         if(!hasData)\r
1209                         {\r
1210                                 throw new InvalidOperationException("No data");\r
1211                         }\r
1212                         if(_resultSet == null)\r
1213                         {\r
1214                                 _resultSet = new object[fieldCount];\r
1215                         }\r
1216                         if(_resultSet[col] == null)\r
1217                         {\r
1218                                 int len;\r
1219                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_SBIGINT, internalBuffer, internalBufferSize, out len);\r
1220                                 if(len == DB2Constants.SQL_NULL_DATA)\r
1221                                 {\r
1222                                         _resultSet[col] = DBNull.Value;\r
1223                                 }\r
1224                                 else\r
1225                                 {\r
1226                                         _resultSet[col] = Marshal.PtrToStructure(internalBuffer, typeof(long));\r
1227                                 }\r
1228                         }               \r
1229                         return _resultSet[col];\r
1230                 }\r
1231 \r
1232                 #endregion\r
1233 \r
1234                 #region GetName\r
1235                 ///\r
1236                 ///GetName, returns the name of the field\r
1237                 ///\r
1238                 public string GetName(int col)\r
1239                 {\r
1240                         if(columnInfo == null)\r
1241                         {\r
1242                                 GetColumnInfo();\r
1243                         }\r
1244                         return columnInfo[col].Colname;\r
1245                 }\r
1246                 #endregion\r
1247 \r
1248                 #region GetOrdinal\r
1249                 ///\r
1250                 /// GetOrdinal, return the index of the named column\r
1251                 /// \r
1252                 public int GetOrdinal(string name)\r
1253                 {\r
1254                         if(columnInfo == null)\r
1255                         {\r
1256                                 GetColumnInfo();\r
1257                         }\r
1258                         object ordinal = columnsNames[name.ToUpper()];\r
1259                         if(ordinal == null)\r
1260                         {\r
1261                                 throw new IndexOutOfRangeException("name");\r
1262                         }\r
1263                         return (int)ordinal;\r
1264                 }\r
1265                 #endregion\r
1266 \r
1267                 #region GetString\r
1268                 ///\r
1269                 /// GetString returns a string\r
1270                 /// \r
1271                 public string GetString(int col)\r
1272                 {\r
1273                         return (string)GetStringInternal(col);\r
1274                 }\r
1275 \r
1276                 public object GetStringInternal(int col)\r
1277                 {\r
1278                         if((col < 0) || (col >= fieldCount))\r
1279                         {\r
1280                                 throw new IndexOutOfRangeException("col");\r
1281                         }\r
1282                         if(!hasData)\r
1283                         {\r
1284                                 throw new InvalidOperationException("No data");\r
1285                         }\r
1286                         if(_resultSet == null)\r
1287                         {\r
1288                                 _resultSet = new object[fieldCount];\r
1289                         }\r
1290                         if(_resultSet[col] == null)\r
1291                         {\r
1292                                 int length;\r
1293                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_WCHAR, (StringBuilder)null, 0, out length);\r
1294                                 if(length == DB2Constants.SQL_NULL_DATA)\r
1295                                 {\r
1296                                         _resultSet[col] = DBNull.Value;\r
1297                                 }\r
1298                                 else\r
1299                                 {\r
1300                                         IntPtr mem = Marshal.AllocHGlobal(length + 2);\r
1301                                         sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_WCHAR, mem, length + 2, out length);\r
1302                                         _resultSet[col] = Marshal.PtrToStringUni(mem);\r
1303                                         Marshal.FreeHGlobal(mem);\r
1304                                 }\r
1305                         }                       \r
1306                         return _resultSet[col];\r
1307                 }\r
1308                 #endregion\r
1309 \r
1310                 #region GetValue\r
1311                 ///\r
1312                 /// GetVCalue, returns an object\r
1313                 /// \r
1314                 public object GetValue(int col)\r
1315                 {\r
1316                         return this[col];\r
1317                 }\r
1318                 #endregion\r
1319 \r
1320                 #region GetValues\r
1321                 ///\r
1322                 /// GetValues returns all columns in the row through the argument, and the number of columns in the return value\r
1323                 /// \r
1324                 public int GetValues(object[] values)\r
1325                 {\r
1326                         int count = Math.Min(fieldCount, values.Length);\r
1327 \r
1328                         for (int i = 0; i < count; i++)\r
1329                         {\r
1330                                 values[i] = this[i];\r
1331                          \r
1332                         }\r
1333                           \r
1334                         return count;\r
1335                 }\r
1336                 #endregion\r
1337 \r
1338                 #region IsDBNull\r
1339                 ///\r
1340                 /// IsDBNull Is the column null\r
1341                 /// \r
1342                 public bool IsDBNull(int col)\r
1343                 {\r
1344                         //Proper implementation once I get the SQLDescribe/SQLBind/SQLFetch stuff in place\r
1345                         return Convert.IsDBNull(this[col]);\r
1346                 }\r
1347                 #endregion\r
1348 \r
1349                 #endregion  ///For IDataRecord\r
1350 \r
1351                 #region private methods\r
1352                 \r
1353                 private DataTable BuildNewSchemaTable()\r
1354                 {\r
1355                         DataTable schemaTable = new DataTable("SchemaTable");\r
1356 \r
1357                         schemaTable.Columns.Add(new DataColumn("ColumnName", typeof(string)));\r
1358                         schemaTable.Columns.Add(new DataColumn("ColumnOrdinal", typeof(int)));\r
1359                         schemaTable.Columns.Add(new DataColumn("ColumnSize", typeof(int)));\r
1360                         schemaTable.Columns.Add(new DataColumn("NumericPrecision", typeof(short)));\r
1361                         schemaTable.Columns.Add(new DataColumn("NumericScale", typeof(short)));\r
1362                         schemaTable.Columns.Add(new DataColumn("DataType", typeof(System.Type)));\r
1363                         schemaTable.Columns.Add(new DataColumn("ProviderType", typeof(int)));\r
1364                         schemaTable.Columns.Add(new DataColumn("IsLong", typeof(bool)));\r
1365                         schemaTable.Columns.Add(new DataColumn("AllowDBNull", typeof(bool)));\r
1366                         schemaTable.Columns.Add(new DataColumn("IsReadOnly", typeof(bool)));\r
1367                         schemaTable.Columns.Add(new DataColumn("IsRowVersion", typeof(bool)));\r
1368                         schemaTable.Columns.Add(new DataColumn("IsUnique", typeof(bool)));\r
1369                         schemaTable.Columns.Add(new DataColumn("IsKey", typeof(bool)));\r
1370                         schemaTable.Columns.Add(new DataColumn("IsKeyColumn", typeof(bool)));\r
1371                         schemaTable.Columns.Add(new DataColumn("IsAutoIncrement", typeof(bool)));\r
1372                         schemaTable.Columns.Add(new DataColumn("BaseSchemaName", typeof(string)));\r
1373                         schemaTable.Columns.Add(new DataColumn("BaseCatalogName", typeof(string)));\r
1374                         schemaTable.Columns.Add(new DataColumn("BaseTableName", typeof(string)));\r
1375                         schemaTable.Columns.Add(new DataColumn("BaseColumnName", typeof(string)));\r
1376 \r
1377                         return schemaTable;\r
1378                 }\r
1379                 #endregion\r
1380                 \r
1381                 private void InitMem(int memSize, ref IntPtr ptr){\r
1382                         if (ptr.ToInt32() == 0){\r
1383                                 unsafe{\r
1384                                         fixed(byte* arr = new byte[memSize]){\r
1385                                                 ptr = new IntPtr(arr); \r
1386                                         }\r
1387                                 }\r
1388                         }       \r
1389                 }\r
1390                 \r
1391                 private Type GetManagedType(int sql_type)\r
1392                 {\r
1393                         switch(sql_type)\r
1394                         {\r
1395                                 case DB2Constants.SQL_INTEGER:\r
1396                                         return typeof(int);\r
1397                                 case DB2Constants.SQL_SMALLINT:\r
1398                                         return typeof(short);\r
1399                                 case DB2Constants.SQL_BIGINT:\r
1400                                         return typeof(long);\r
1401                                 case DB2Constants.SQL_DOUBLE:\r
1402                                         return typeof(double);\r
1403                                 case DB2Constants.SQL_DECIMAL:\r
1404                                         return typeof(decimal);\r
1405                                 case DB2Constants.SQL_DATETIME:\r
1406                                 case DB2Constants.SQL_TYPE_DATE:\r
1407                                 case DB2Constants.SQL_TYPE_TIMESTAMP:\r
1408                                         return typeof(DateTime);\r
1409                                 case DB2Constants.SQL_TYPE_TIME:\r
1410                                         return typeof(TimeSpan);\r
1411                                 case DB2Constants.SQL_CHAR:\r
1412                                 case DB2Constants.SQL_VARCHAR:\r
1413                                 case DB2Constants.SQL_TYPE_CLOB:\r
1414                                         return typeof(string);\r
1415                                 case DB2Constants.SQL_TYPE_BLOB:\r
1416                                 case DB2Constants.SQL_TYPE_BINARY:\r
1417                                 case DB2Constants.SQL_LONGVARBINARY:\r
1418                                 case DB2Constants.SQL_VARBINARY:\r
1419                                         return typeof(byte[]);\r
1420                         }\r
1421                         throw new NotImplementedException("Unknown SQL type " + sql_type);\r
1422                 }\r
1423                 \r
1424                 private bool IsLong(short sql_type)\r
1425                 {\r
1426                         switch(sql_type)\r
1427                         {\r
1428                                 case DB2Constants.SQL_TYPE_CLOB:\r
1429                                 case DB2Constants.SQL_TYPE_BLOB:\r
1430                                         return true;\r
1431                         }\r
1432                         return false;\r
1433                 }\r
1434                 private object GetBlobDataInternal(int col)\r
1435                 {\r
1436                         if((col < 0) || (col >= fieldCount))\r
1437                         {\r
1438                                 throw new IndexOutOfRangeException("col");\r
1439                         }\r
1440                         if(!hasData)\r
1441                         {\r
1442                                 throw new InvalidOperationException("No data");\r
1443                         }\r
1444                         if(_resultSet == null)\r
1445                         {\r
1446                                 _resultSet = new object[fieldCount];\r
1447                         }\r
1448                         if(_resultSet[col] == null)\r
1449                         {\r
1450                                 int length;\r
1451                                 short sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_BINARY, (StringBuilder)null, 0, out length);\r
1452                                 if(length == DB2Constants.SQL_NULL_DATA)\r
1453                                 {\r
1454                                         _resultSet[col] = DBNull.Value;\r
1455                                 }\r
1456                                 else\r
1457                                 {\r
1458                                         byte[] result = new byte[length];\r
1459                                         sqlRet = DB2CLIWrapper.SQLGetData(this.hwndStmt, (short)(col + 1), (short)DB2Constants.SQL_C_TYPE_BINARY, result, length, out length);\r
1460                                         _resultSet[col] = result;\r
1461                                 }\r
1462                         }                       \r
1463                         return _resultSet[col];\r
1464                 }\r
1465         }\r
1466 \r
1467 }\r
1468 #endregion\r