OdbcDataReader.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. //
  2. // System.Data.Odbc.OdbcDataReader
  3. //
  4. // Author:
  5. // Brian Ritchie ([email protected])
  6. // Daniel Morgan <[email protected]>
  7. // Sureshkumar T <[email protected]> (2004)
  8. //
  9. // Copyright (C) Brian Ritchie, 2002
  10. // Copyright (C) Daniel Morgan, 2002
  11. //
  12. //
  13. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System.Collections;
  35. using System.ComponentModel;
  36. using System.Data;
  37. using System.Data.Common;
  38. using System.Text;
  39. namespace System.Data.Odbc
  40. {
  41. #if NET_2_0
  42. public sealed class OdbcDataReader : DbDataReader
  43. #else
  44. public sealed class OdbcDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
  45. #endif
  46. {
  47. #region Fields
  48. private OdbcCommand command;
  49. private bool open;
  50. private int currentRow;
  51. private OdbcColumn[] cols;
  52. private IntPtr hstmt;
  53. private int _recordsAffected = -1;
  54. bool disposed = false;
  55. private DataTable _dataTableSchema;
  56. private CommandBehavior behavior;
  57. #endregion
  58. #region Constructors
  59. internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior)
  60. {
  61. this.command = command;
  62. this.CommandBehavior = behavior;
  63. open = true;
  64. currentRow = -1;
  65. hstmt = command.hStmt;
  66. // Init columns array;
  67. short colcount = 0;
  68. libodbc.SQLNumResultCols (hstmt, ref colcount);
  69. cols = new OdbcColumn [colcount];
  70. GetSchemaTable ();
  71. }
  72. internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior,
  73. int recordAffected) : this (command, behavior)
  74. {
  75. _recordsAffected = recordAffected;
  76. }
  77. #endregion
  78. #region Properties
  79. private CommandBehavior CommandBehavior
  80. {
  81. get { return behavior; }
  82. set { value = behavior; }
  83. }
  84. public
  85. #if NET_2_0
  86. override
  87. #endif // NET_2_0
  88. int Depth {
  89. get {
  90. return 0; // no nested selects supported
  91. }
  92. }
  93. public
  94. #if NET_2_0
  95. override
  96. #endif // NET_2_0
  97. int FieldCount {
  98. get {
  99. return cols.Length;
  100. }
  101. }
  102. public
  103. #if NET_2_0
  104. override
  105. #endif // NET_2_0
  106. bool IsClosed {
  107. get {
  108. return !open;
  109. }
  110. }
  111. public
  112. #if NET_2_0
  113. override
  114. #endif // NET_2_0
  115. object this[string name] {
  116. get {
  117. int pos;
  118. if (currentRow == -1)
  119. throw new InvalidOperationException ();
  120. pos = ColIndex(name);
  121. if (pos == -1)
  122. throw new IndexOutOfRangeException ();
  123. return this[pos];
  124. }
  125. }
  126. public
  127. #if NET_2_0
  128. override
  129. #endif // NET_2_0
  130. object this [int index] {
  131. get {
  132. return (object) GetValue (index);
  133. }
  134. }
  135. public
  136. #if NET_2_0
  137. override
  138. #endif // NET_2_0
  139. int RecordsAffected {
  140. get {
  141. return _recordsAffected;
  142. }
  143. }
  144. [MonoTODO]
  145. public
  146. #if NET_2_0
  147. override
  148. #endif // NET_2_0
  149. bool HasRows {
  150. get { throw new NotImplementedException(); }
  151. }
  152. #endregion
  153. #region Methods
  154. private int ColIndex (string colname)
  155. {
  156. int i = 0;
  157. foreach (OdbcColumn col in cols)
  158. {
  159. if (col != null) {
  160. if (col.ColumnName == colname)
  161. return i;
  162. if (String.Compare (col.ColumnName, colname, true) == 0)
  163. return i;
  164. }
  165. i++;
  166. }
  167. return -1;
  168. }
  169. // Dynamically load column descriptions as needed.
  170. private OdbcColumn GetColumn (int ordinal)
  171. {
  172. if (cols [ordinal] == null) {
  173. short bufsize = 255;
  174. byte [] colname_buffer = new byte [bufsize];
  175. string colname;
  176. short colname_size = 0;
  177. uint ColSize = 0;
  178. short DecDigits = 0, Nullable = 0, dt = 0;
  179. OdbcReturn ret = libodbc.SQLDescribeCol (hstmt, Convert.ToUInt16 (ordinal + 1),
  180. colname_buffer, bufsize, ref colname_size, ref dt, ref ColSize,
  181. ref DecDigits, ref Nullable);
  182. if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
  183. throw new OdbcException (new OdbcError ("SQLDescribeCol", OdbcHandleType.Stmt, hstmt));
  184. colname = System.Text.Encoding.Default.GetString (colname_buffer);
  185. colname = colname.Replace ((char) 0, ' ').Trim ();
  186. OdbcColumn c = new OdbcColumn (colname, (SQL_TYPE) dt);
  187. c.AllowDBNull = (Nullable != 0);
  188. c.Digits = DecDigits;
  189. if (c.IsVariableSizeType)
  190. c.MaxLength = (int) ColSize;
  191. cols [ordinal] = c;
  192. }
  193. return cols [ordinal];
  194. }
  195. public
  196. #if NET_2_0
  197. override
  198. #endif // NET_2_0
  199. void Close ()
  200. {
  201. // FIXME : have to implement output parameter binding
  202. open = false;
  203. currentRow = -1;
  204. this.command.FreeIfNotPrepared ();
  205. if ((this.CommandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection) {
  206. this.command.Connection.Close ();
  207. }
  208. }
  209. ~OdbcDataReader ()
  210. {
  211. this.Dispose (false);
  212. }
  213. public
  214. #if NET_2_0
  215. override
  216. #endif // NET_2_0
  217. bool GetBoolean (int ordinal)
  218. {
  219. return (bool) GetValue(ordinal);
  220. }
  221. public
  222. #if NET_2_0
  223. override
  224. #endif // NET_2_0
  225. byte GetByte (int ordinal)
  226. {
  227. return (byte) Convert.ToByte(GetValue(ordinal));
  228. }
  229. public
  230. #if NET_2_0
  231. override
  232. #endif // NET_2_0
  233. long GetBytes (int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
  234. {
  235. OdbcReturn ret = OdbcReturn.Error;
  236. bool copyBuffer = false;
  237. int returnVal = 0, outsize = 0;
  238. byte [] tbuff = new byte [length+1];
  239. length = buffer == null ? 0 : length;
  240. ret=libodbc.SQLGetData (hstmt, (ushort) (ordinal+1), SQL_C_TYPE.BINARY, tbuff, length,
  241. ref outsize);
  242. if (ret == OdbcReturn.NoData)
  243. return 0;
  244. if ( (ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
  245. throw new OdbcException (new OdbcError ("SQLGetData", OdbcHandleType.Stmt, hstmt));
  246. OdbcError odbcErr = null;
  247. if ( (ret == OdbcReturn.SuccessWithInfo))
  248. odbcErr = new OdbcError ("SQLGetData", OdbcHandleType.Stmt, hstmt);
  249. if (buffer == null)
  250. return outsize; //if buffer is null,return length of the field
  251. if (ret == OdbcReturn.SuccessWithInfo) {
  252. if (outsize == (int) OdbcLengthIndicator.NoTotal)
  253. copyBuffer = true;
  254. else if (outsize == (int) OdbcLengthIndicator.NullData) {
  255. copyBuffer = false;
  256. returnVal = -1;
  257. } else {
  258. string sqlstate = odbcErr.SQLState;
  259. //SQLState: String Data, Right truncated
  260. if (sqlstate != libodbc.SQLSTATE_RIGHT_TRUNC)
  261. throw new OdbcException ( odbcErr);
  262. copyBuffer = true;
  263. }
  264. } else {
  265. copyBuffer = outsize == -1 ? false : true;
  266. returnVal = outsize;
  267. }
  268. if (copyBuffer) {
  269. int i = 0;
  270. while (tbuff [i] != libodbc.C_NULL) {
  271. buffer [bufferIndex + i] = tbuff [i];
  272. i++;
  273. }
  274. returnVal = i;
  275. }
  276. return returnVal;
  277. }
  278. public
  279. #if NET_2_0
  280. override
  281. #endif // NET_2_0
  282. char GetChar (int ordinal)
  283. {
  284. return (char) GetValue (ordinal);
  285. }
  286. [MonoTODO]
  287. public
  288. #if NET_2_0
  289. override
  290. #endif // NET_2_0
  291. long GetChars (int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
  292. {
  293. throw new NotImplementedException ();
  294. }
  295. [MonoTODO]
  296. [EditorBrowsableAttribute (EditorBrowsableState.Never)]
  297. public
  298. #if NET_2_0
  299. new
  300. #endif // NET_2_0
  301. IDataReader GetData (int ordinal)
  302. {
  303. throw new NotImplementedException ();
  304. }
  305. public
  306. #if NET_2_0
  307. override
  308. #endif // NET_2_0
  309. string GetDataTypeName (int index)
  310. {
  311. return GetColumn (index).OdbcType.ToString ();
  312. }
  313. public DateTime GetDate (int ordinal) {
  314. return GetDateTime (ordinal);
  315. }
  316. public
  317. #if NET_2_0
  318. override
  319. #endif // NET_2_0
  320. DateTime GetDateTime (int ordinal)
  321. {
  322. return (DateTime) GetValue (ordinal);
  323. }
  324. public
  325. #if NET_2_0
  326. override
  327. #endif // NET_2_0
  328. decimal GetDecimal (int ordinal)
  329. {
  330. return (decimal) GetValue (ordinal);
  331. }
  332. public
  333. #if NET_2_0
  334. override
  335. #endif // NET_2_0
  336. double GetDouble (int ordinal)
  337. {
  338. return (double) GetValue (ordinal);
  339. }
  340. public
  341. #if NET_2_0
  342. override
  343. #endif // NET_2_0
  344. Type GetFieldType (int index)
  345. {
  346. return GetColumn(index).DataType;
  347. }
  348. public
  349. #if NET_2_0
  350. override
  351. #endif // NET_2_0
  352. float GetFloat (int ordinal)
  353. {
  354. return (float) GetValue (ordinal);
  355. }
  356. [MonoTODO]
  357. public
  358. #if NET_2_0
  359. override
  360. #endif // NET_2_0
  361. Guid GetGuid (int ordinal)
  362. {
  363. throw new NotImplementedException ();
  364. }
  365. public
  366. #if NET_2_0
  367. override
  368. #endif // NET_2_0
  369. short GetInt16 (int ordinal)
  370. {
  371. return (short) GetValue (ordinal);
  372. }
  373. public
  374. #if NET_2_0
  375. override
  376. #endif // NET_2_0
  377. int GetInt32 (int ordinal)
  378. {
  379. return (int) GetValue (ordinal);
  380. }
  381. public
  382. #if NET_2_0
  383. override
  384. #endif // NET_2_0
  385. long GetInt64 (int ordinal)
  386. {
  387. return (long) GetValue (ordinal);
  388. }
  389. public
  390. #if NET_2_0
  391. override
  392. #endif // NET_2_0
  393. string GetName (int index)
  394. {
  395. return GetColumn(index).ColumnName;
  396. }
  397. public
  398. #if NET_2_0
  399. override
  400. #endif // NET_2_0
  401. int GetOrdinal (string name)
  402. {
  403. int i=ColIndex(name);
  404. if (i==-1)
  405. throw new IndexOutOfRangeException ();
  406. else
  407. return i;
  408. }
  409. [MonoTODO]
  410. public
  411. #if NET_2_0
  412. override
  413. #endif // NET_2_0
  414. DataTable GetSchemaTable()
  415. {
  416. // FIXME :
  417. // * Map OdbcType to System.Type and assign to DataType.
  418. // This will eliminate the need for IsStringType in
  419. // OdbcColumn.
  420. if (_dataTableSchema != null)
  421. return _dataTableSchema;
  422. DataTable dataTableSchema = null;
  423. // Only Results from SQL SELECT Queries
  424. // get a DataTable for schema of the result
  425. // otherwise, DataTable is null reference
  426. if(cols.Length > 0)
  427. {
  428. dataTableSchema = new DataTable ();
  429. dataTableSchema.Columns.Add ("ColumnName", typeof (string));
  430. dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
  431. dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
  432. dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
  433. dataTableSchema.Columns.Add ("NumericScale", typeof (int));
  434. dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
  435. dataTableSchema.Columns.Add ("IsKey", typeof (bool));
  436. DataColumn dc = dataTableSchema.Columns["IsKey"];
  437. dc.AllowDBNull = true; // IsKey can have a DBNull
  438. dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
  439. dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
  440. dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
  441. dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
  442. dataTableSchema.Columns.Add ("DataType", typeof(Type));
  443. dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
  444. dataTableSchema.Columns.Add ("ProviderType", typeof (int));
  445. dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
  446. dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
  447. dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
  448. dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
  449. dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
  450. dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
  451. dataTableSchema.Columns.Add ("IsLong", typeof (bool));
  452. dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
  453. DataRow schemaRow;
  454. for (int i = 0; i < cols.Length; i += 1 )
  455. {
  456. string baseTableName = String.Empty;
  457. bool isKey = false;
  458. OdbcColumn col=GetColumn(i);
  459. schemaRow = dataTableSchema.NewRow ();
  460. dataTableSchema.Rows.Add (schemaRow);
  461. schemaRow ["ColumnName"] = col.ColumnName;
  462. schemaRow ["ColumnOrdinal"] = i;
  463. schemaRow ["ColumnSize"] = col.MaxLength;
  464. schemaRow ["NumericPrecision"] = GetColumnAttribute (i+1, FieldIdentifier.Precision);
  465. schemaRow ["NumericScale"] = GetColumnAttribute (i+1, FieldIdentifier.Scale);
  466. schemaRow ["BaseTableName"] = GetColumnAttributeStr (i+1, FieldIdentifier.TableName);
  467. schemaRow ["BaseSchemaName"] = GetColumnAttributeStr (i+1, FieldIdentifier.SchemaName);
  468. schemaRow ["BaseCatalogName"] = GetColumnAttributeStr (i+1, FieldIdentifier.CatelogName);
  469. schemaRow ["BaseColumnName"] = GetColumnAttributeStr (i+1, FieldIdentifier.BaseColumnName);
  470. schemaRow ["DataType"] = col.DataType;
  471. schemaRow ["IsUnique"] = false;
  472. schemaRow ["IsKey"] = DBNull.Value;
  473. schemaRow ["AllowDBNull"] = GetColumnAttribute (i+1, FieldIdentifier.Nullable) != libodbc.SQL_NO_NULLS;
  474. schemaRow ["ProviderType"] = (int) col.OdbcType;
  475. schemaRow ["IsAutoIncrement"] = GetColumnAttribute (i+1, FieldIdentifier.AutoUniqueValue) == libodbc.SQL_TRUE;
  476. schemaRow ["IsExpression"] = schemaRow.IsNull ("BaseTableName") || (string) schemaRow ["BaseTableName"] == String.Empty;
  477. schemaRow ["IsAliased"] = (string) schemaRow ["BaseColumnName"] != (string) schemaRow ["ColumnName"];
  478. schemaRow ["IsReadOnly"] = ((bool) schemaRow ["IsExpression"]
  479. || GetColumnAttribute (i+1, FieldIdentifier.Updatable) == libodbc.SQL_ATTR_READONLY);
  480. // FIXME: all of these
  481. schemaRow ["IsIdentity"] = false;
  482. schemaRow ["IsRowVersion"] = false;
  483. schemaRow ["IsHidden"] = false;
  484. schemaRow ["IsLong"] = false;
  485. // FIXME: according to Brian,
  486. // this does not work on MS .NET
  487. // however, we need it for Mono
  488. // for now
  489. // schemaRow.AcceptChanges();
  490. }
  491. // set primary keys
  492. DataRow [] rows = dataTableSchema.Select ("BaseTableName <> ''",
  493. "BaseCatalogName, BaseSchemaName, BaseTableName ASC");
  494. string lastTableName = String.Empty,
  495. lastSchemaName = String.Empty,
  496. lastCatalogName = String.Empty;
  497. string [] keys = null; // assumed to be sorted.
  498. foreach (DataRow row in rows) {
  499. string tableName = (string) row ["BaseTableName"];
  500. string schemaName = (string) row ["BaseSchemaName"];
  501. string catalogName = (string) row ["BaseCatalogName"];
  502. if (tableName != lastTableName || schemaName != lastSchemaName
  503. || catalogName != lastCatalogName)
  504. keys = GetPrimaryKeys (catalogName, schemaName, tableName);
  505. if (keys != null &&
  506. Array.BinarySearch (keys, (string) row ["BaseColumnName"]) >= 0) {
  507. row ["IsKey"] = true;
  508. row ["IsUnique"] = true;
  509. row ["AllowDBNull"] = false;
  510. GetColumn ( ColIndex ( (string) row ["ColumnName"])).AllowDBNull = false;
  511. }
  512. lastTableName = tableName;
  513. lastSchemaName = schemaName;
  514. lastCatalogName = catalogName;
  515. }
  516. dataTableSchema.AcceptChanges();
  517. }
  518. return (_dataTableSchema = dataTableSchema);
  519. }
  520. public
  521. #if NET_2_0
  522. override
  523. #endif // NET_2_0
  524. string GetString (int ordinal)
  525. {
  526. return (string) GetValue (ordinal);
  527. }
  528. [MonoTODO]
  529. public TimeSpan GetTime (int ordinal)
  530. {
  531. throw new NotImplementedException ();
  532. }
  533. public
  534. #if NET_2_0
  535. override
  536. #endif // NET_2_0
  537. object GetValue (int ordinal)
  538. {
  539. if (currentRow == -1)
  540. throw new IndexOutOfRangeException ();
  541. if (ordinal > cols.Length-1 || ordinal < 0)
  542. throw new IndexOutOfRangeException ();
  543. OdbcReturn ret;
  544. int outsize = 0, bufsize;
  545. byte[] buffer;
  546. OdbcColumn col = GetColumn (ordinal);
  547. object DataValue = null;
  548. ushort ColIndex = Convert.ToUInt16 (ordinal+1);
  549. // Check cached values
  550. if (col.Value == null) {
  551. // odbc help file
  552. // mk:@MSITStore:C:\program%20files\Microsoft%20Data%20Access%20SDK\Docs\odbc.chm::/htm/odbcc_data_types.htm
  553. switch (col.OdbcType) {
  554. case OdbcType.Bit:
  555. short bit_data = 0;
  556. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref bit_data, 0, ref outsize);
  557. if (outsize != (int) OdbcLengthIndicator.NullData)
  558. DataValue = bit_data == 0 ? "False" : "True";
  559. break;
  560. case OdbcType.Numeric:
  561. case OdbcType.Decimal:
  562. bufsize = 50;
  563. buffer = new byte [bufsize]; // According to sqlext.h, use SQL_CHAR for decimal.
  564. // FIXME : use Numeric.
  565. ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.CHAR, buffer, bufsize, ref outsize);
  566. if (outsize!=-1) {
  567. byte [] temp = new byte [outsize];
  568. for (int i = 0;i<outsize;i++)
  569. temp[i] = buffer[i];
  570. DataValue = Decimal.Parse(System.Text.Encoding.Default.GetString(temp));
  571. }
  572. break;
  573. case OdbcType.TinyInt:
  574. short short_data = 0;
  575. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref short_data, 0, ref outsize);
  576. DataValue = System.Convert.ToByte(short_data);
  577. break;
  578. case OdbcType.Int:
  579. int int_data = 0;
  580. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref int_data, 0, ref outsize);
  581. DataValue = int_data;
  582. break;
  583. case OdbcType.SmallInt:
  584. short sint_data = 0;
  585. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref sint_data, 0, ref outsize);
  586. DataValue = sint_data;
  587. break;
  588. case OdbcType.BigInt:
  589. long long_data = 0;
  590. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref long_data, 0, ref outsize);
  591. DataValue = long_data;
  592. break;
  593. case OdbcType.NText:
  594. case OdbcType.NVarChar:
  595. bufsize = (col.MaxLength < 127 ? (col.MaxLength*2+1) : 255);
  596. buffer = new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for both char and varchar
  597. StringBuilder sb = new StringBuilder ();
  598. do {
  599. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
  600. if (ret == OdbcReturn.Error)
  601. break;
  602. if (ret != OdbcReturn.NoData && outsize!=-1) {
  603. if (outsize < bufsize)
  604. sb.Append (System.Text.Encoding.Unicode.GetString(buffer,0,outsize));
  605. else
  606. sb.Append (System.Text.Encoding.Unicode.GetString(buffer,0,bufsize));
  607. }
  608. } while (ret != OdbcReturn.NoData);
  609. DataValue = sb.ToString ();
  610. break;
  611. case OdbcType.Text:
  612. case OdbcType.VarChar:
  613. bufsize = (col.MaxLength < 255 ? (col.MaxLength+1) : 255);
  614. buffer = new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for both char and varchar
  615. StringBuilder sb1 = new StringBuilder ();
  616. do {
  617. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
  618. if (ret == OdbcReturn.Error)
  619. break;
  620. if (ret != OdbcReturn.NoData && outsize!=-1) {
  621. if (outsize < bufsize)
  622. sb1.Append (System.Text.Encoding.Default.GetString(buffer,0,outsize));
  623. else
  624. sb1.Append (System.Text.Encoding.Default.GetString(buffer,0,bufsize));
  625. }
  626. } while (ret != OdbcReturn.NoData);
  627. DataValue = sb1.ToString ();
  628. break;
  629. case OdbcType.Char:
  630. char charData = ' ';
  631. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref charData, 0, ref outsize);
  632. DataValue = charData;
  633. break;
  634. case OdbcType.Real:
  635. float float_data = 0;
  636. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref float_data, 0, ref outsize);
  637. DataValue = float_data;
  638. break;
  639. case OdbcType.Double:
  640. double double_data = 0;
  641. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref double_data, 0, ref outsize);
  642. DataValue = double_data;
  643. break;
  644. case OdbcType.Timestamp:
  645. case OdbcType.DateTime:
  646. case OdbcType.Date:
  647. case OdbcType.Time:
  648. OdbcTimestamp ts_data = new OdbcTimestamp();
  649. ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref ts_data, 0, ref outsize);
  650. if (outsize!=-1) // This means SQL_NULL_DATA
  651. DataValue = new DateTime(ts_data.year,ts_data.month,ts_data.day,ts_data.hour,
  652. ts_data.minute,ts_data.second,Convert.ToInt32(ts_data.fraction));
  653. break;
  654. case OdbcType.VarBinary :
  655. case OdbcType.Image :
  656. bufsize = (col.MaxLength < 255 ? col.MaxLength : 255);
  657. buffer= new byte [bufsize];
  658. ArrayList al = new ArrayList ();
  659. do {
  660. ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.BINARY, buffer, bufsize, ref outsize);
  661. if (ret == OdbcReturn.Error)
  662. break;
  663. if (ret != OdbcReturn.NoData && outsize!=-1) {
  664. if (outsize < bufsize) {
  665. byte[] tmparr = new byte [outsize];
  666. Array.Copy (buffer, 0, tmparr, 0, outsize);
  667. al.AddRange (tmparr);
  668. } else
  669. al.AddRange (buffer);
  670. }
  671. } while (ret != OdbcReturn.NoData);
  672. DataValue = al.ToArray (typeof (byte));
  673. break;
  674. case OdbcType.Binary :
  675. bufsize = col.MaxLength;
  676. buffer = new byte [bufsize];
  677. long read = GetBytes (ordinal, 0, buffer, 0, bufsize);
  678. ret = OdbcReturn.Success;
  679. DataValue = buffer;
  680. break;
  681. default:
  682. bufsize = 255;
  683. buffer = new byte[bufsize];
  684. ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.CHAR, buffer, bufsize, ref outsize);
  685. if (outsize != (int) OdbcLengthIndicator.NullData)
  686. if (! (ret == OdbcReturn.SuccessWithInfo
  687. && outsize == (int) OdbcLengthIndicator.NoTotal))
  688. DataValue = System.Text.Encoding.Default.GetString(buffer, 0, outsize);
  689. break;
  690. }
  691. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo) && (ret!=OdbcReturn.NoData))
  692. throw new OdbcException(new OdbcError("SQLGetData",OdbcHandleType.Stmt,hstmt));
  693. if (outsize==-1) // This means SQL_NULL_DATA
  694. col.Value = DBNull.Value;
  695. else
  696. col.Value = DataValue;
  697. }
  698. return col.Value;
  699. }
  700. public
  701. #if NET_2_0
  702. override
  703. #endif // NET_2_0
  704. int GetValues (object[] values)
  705. {
  706. int numValues = 0;
  707. // copy values
  708. for (int i = 0; i < values.Length; i++) {
  709. if (i < FieldCount) {
  710. values[i] = GetValue (i);
  711. }
  712. else {
  713. values[i] = null;
  714. }
  715. }
  716. // get number of object instances in array
  717. if (values.Length < FieldCount)
  718. numValues = values.Length;
  719. else if (values.Length == FieldCount)
  720. numValues = FieldCount;
  721. else
  722. numValues = FieldCount;
  723. return numValues;
  724. }
  725. #if ONLY_1_1
  726. void IDisposable.Dispose ()
  727. {
  728. Dispose (true);
  729. GC.SuppressFinalize (this);
  730. }
  731. IEnumerator IEnumerable.GetEnumerator ()
  732. {
  733. return new DbEnumerator (this);
  734. }
  735. #endif // ONLY_1_1
  736. #if NET_2_0
  737. public override IEnumerator GetEnumerator ()
  738. {
  739. return new DbEnumerator (this);
  740. }
  741. #endif
  742. #if NET_2_0
  743. protected override
  744. #endif
  745. void Dispose (bool disposing)
  746. {
  747. if (disposed)
  748. return;
  749. if (disposing) {
  750. // dispose managed resources
  751. Close ();
  752. }
  753. command = null;
  754. cols = null;
  755. _dataTableSchema = null;
  756. disposed = true;
  757. }
  758. public
  759. #if NET_2_0
  760. override
  761. #endif // NET_2_0
  762. bool IsDBNull (int ordinal)
  763. {
  764. return (GetValue (ordinal) is DBNull);
  765. }
  766. /// <remarks>
  767. /// Move to the next result set.
  768. /// </remarks>
  769. public
  770. #if NET_2_0
  771. override
  772. #endif // NET_2_0
  773. bool NextResult ()
  774. {
  775. OdbcReturn ret = OdbcReturn.Success;
  776. ret = libodbc.SQLMoreResults (hstmt);
  777. if (ret == OdbcReturn.Success) {
  778. short colcount = 0;
  779. libodbc.SQLNumResultCols (hstmt, ref colcount);
  780. cols = new OdbcColumn [colcount];
  781. _dataTableSchema = null; // force fresh creation
  782. GetSchemaTable ();
  783. }
  784. return (ret==OdbcReturn.Success);
  785. }
  786. /// <remarks>
  787. /// Load the next row in the current result set.
  788. /// </remarks>
  789. private bool NextRow ()
  790. {
  791. OdbcReturn ret=libodbc.SQLFetch (hstmt);
  792. if (ret != OdbcReturn.Success)
  793. currentRow = -1;
  794. else
  795. currentRow++;
  796. // Clear cached values from last record
  797. foreach (OdbcColumn col in cols)
  798. {
  799. if (col != null)
  800. col.Value = null;
  801. }
  802. return (ret == OdbcReturn.Success);
  803. }
  804. private int GetColumnAttribute (int column, FieldIdentifier fieldId)
  805. {
  806. OdbcReturn ret = OdbcReturn.Error;
  807. byte [] buffer = new byte [255];
  808. int outsize = 0;
  809. int val = 0;
  810. ret = libodbc.SQLColAttribute (hstmt, column, fieldId,
  811. buffer, buffer.Length,
  812. ref outsize, ref val);
  813. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  814. throw new OdbcException (new OdbcError ("SQLColAttribute",
  815. OdbcHandleType.Stmt,
  816. hstmt)
  817. );
  818. return val;
  819. }
  820. private string GetColumnAttributeStr (int column, FieldIdentifier fieldId)
  821. {
  822. OdbcReturn ret = OdbcReturn.Error;
  823. byte [] buffer = new byte [255];
  824. int outsize = 0;
  825. int val = 0;
  826. ret = libodbc.SQLColAttribute (hstmt, column, fieldId,
  827. buffer, buffer.Length,
  828. ref outsize, ref val);
  829. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  830. throw new OdbcException (new OdbcError ("SQLColAttribute",
  831. OdbcHandleType.Stmt,
  832. hstmt)
  833. );
  834. string value = "";
  835. if (outsize > 0)
  836. value = Encoding.Default.GetString (buffer, 0, outsize);
  837. return value;
  838. }
  839. private string [] GetPrimaryKeys (string catalog, string schema, string table)
  840. {
  841. if (cols.Length <= 0)
  842. return new string [0];
  843. ArrayList keys = null;
  844. try {
  845. keys = GetPrimaryKeysBySQLPrimaryKey (catalog, schema, table);
  846. } catch (OdbcException){
  847. try {
  848. keys = GetPrimaryKeysBySQLStatistics (catalog, schema, table);
  849. } catch (OdbcException) {
  850. }
  851. }
  852. keys.Sort ();
  853. return (string []) keys.ToArray (typeof (string));
  854. }
  855. private ArrayList GetPrimaryKeysBySQLPrimaryKey (string catalog, string schema, string table)
  856. {
  857. ArrayList keys = new ArrayList ();
  858. IntPtr handle = IntPtr.Zero;
  859. OdbcReturn ret;
  860. try {
  861. ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt,
  862. command.Connection.hDbc, ref handle);
  863. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  864. throw new OdbcException(new OdbcError("SQLAllocHandle",
  865. OdbcHandleType.Dbc,
  866. command.Connection.hDbc));
  867. ret = libodbc.SQLPrimaryKeys (handle, catalog, -3,
  868. schema, -3,
  869. table, -3);
  870. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  871. throw new OdbcException (new OdbcError ("SQLPrimaryKeys", OdbcHandleType.Stmt, handle));
  872. int length = 0;
  873. byte [] primaryKey = new byte [255];
  874. ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.CHAR, primaryKey, primaryKey.Length, ref length);
  875. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  876. throw new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
  877. int i = 0;
  878. while (true) {
  879. ret = libodbc.SQLFetch (handle);
  880. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  881. break;
  882. string pkey = Encoding.Default.GetString (primaryKey, 0, length);
  883. keys.Add (pkey);
  884. }
  885. } finally {
  886. if (handle != IntPtr.Zero) {
  887. ret = libodbc.SQLFreeStmt (handle, libodbc.SQLFreeStmtOptions.Close);
  888. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  889. throw new OdbcException(new OdbcError("SQLFreeStmt",OdbcHandleType.Stmt,handle));
  890. ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, handle);
  891. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  892. throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,handle));
  893. }
  894. }
  895. return keys;
  896. }
  897. private unsafe ArrayList GetPrimaryKeysBySQLStatistics (string catalog, string schema, string table)
  898. {
  899. ArrayList keys = new ArrayList ();
  900. IntPtr handle = IntPtr.Zero;
  901. OdbcReturn ret;
  902. try {
  903. ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt,
  904. command.Connection.hDbc, ref handle);
  905. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  906. throw new OdbcException(new OdbcError("SQLAllocHandle",
  907. OdbcHandleType.Dbc,
  908. command.Connection.hDbc));
  909. ret = libodbc.SQLStatistics (handle, catalog, -3,
  910. schema, -3,
  911. table, -3,
  912. libodbc.SQL_INDEX_UNIQUE,
  913. libodbc.SQL_QUICK);
  914. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  915. throw new OdbcException (new OdbcError ("SQLStatistics", OdbcHandleType.Stmt, handle));
  916. // NON_UNIQUE
  917. int nonUniqueLength = 0;
  918. short nonUnique = libodbc.SQL_FALSE;
  919. ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.SHORT, ref (short) nonUnique, sizeof (short), ref nonUniqueLength);
  920. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  921. throw new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
  922. // COLUMN_NAME
  923. int length = 0;
  924. byte [] colName = new byte [255];
  925. ret = libodbc.SQLBindCol (handle, 9, SQL_C_TYPE.CHAR, colName, colName.Length, ref length);
  926. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  927. throw new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
  928. int i = 0;
  929. while (true) {
  930. ret = libodbc.SQLFetch (handle);
  931. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  932. break;
  933. if (nonUnique == libodbc.SQL_TRUE) {
  934. string pkey = Encoding.Default.GetString (colName, 0, length);
  935. keys.Add (pkey);
  936. break;
  937. }
  938. }
  939. } finally {
  940. if (handle != IntPtr.Zero) {
  941. ret = libodbc.SQLFreeStmt (handle, libodbc.SQLFreeStmtOptions.Close);
  942. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  943. throw new OdbcException(new OdbcError("SQLFreeStmt",OdbcHandleType.Stmt,handle));
  944. ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, handle);
  945. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  946. throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,handle));
  947. }
  948. }
  949. return keys;
  950. }
  951. public
  952. #if NET_2_0
  953. override
  954. #endif // NET_2_0
  955. bool Read ()
  956. {
  957. return NextRow ();
  958. }
  959. #if NET_2_0
  960. [MonoTODO]
  961. public override object GetProviderSpecificValue (int i)
  962. {
  963. throw new NotImplementedException ();
  964. }
  965. [MonoTODO]
  966. public override int GetProviderSpecificValues (object[] values)
  967. {
  968. throw new NotImplementedException ();
  969. }
  970. [MonoTODO]
  971. public override Type GetProviderSpecificFieldType (int i)
  972. {
  973. throw new NotImplementedException ();
  974. }
  975. #endif // NET_2_0
  976. #endregion
  977. }
  978. }