OracleParameter.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. //
  2. // OracleParameter.cs
  3. //
  4. // Part of the Mono class libraries at
  5. // mcs/class/System.Data.OracleClient/System.Data.OracleClient
  6. //
  7. // Assembly: System.Data.OracleClient.dll
  8. // Namespace: System.Data.OracleClient
  9. //
  10. // Authors:
  11. // Tim Coleman <[email protected]>
  12. // Daniel Moragn <[email protected]>
  13. //
  14. // Copyright (C) Tim Coleman , 2003
  15. // Copyright (C) Daniel Morgan, 2005
  16. //
  17. // Licensed under the MIT/X11 License.
  18. //
  19. using System;
  20. using System.Collections;
  21. using System.ComponentModel;
  22. using System.Data;
  23. using System.Data.OracleClient.Oci;
  24. using System.Globalization;
  25. using System.Runtime.InteropServices;
  26. using System.Text;
  27. namespace System.Data.OracleClient {
  28. [TypeConverter (typeof(OracleParameter.OracleParameterConverter))]
  29. public sealed class OracleParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
  30. {
  31. #region Fields
  32. string name;
  33. OracleType oracleType = OracleType.VarChar;
  34. OciDataType ociType;
  35. int size;
  36. ParameterDirection direction = ParameterDirection.Input;
  37. bool isNullable;
  38. byte precision;
  39. byte scale;
  40. string srcColumn;
  41. DataRowVersion srcVersion;
  42. DbType dbType = DbType.AnsiString;
  43. int offset = 0;
  44. bool sizeSet = false;
  45. object value = null;
  46. OciLobLocator lobLocator = null; // only if Blob or Clob
  47. OracleParameterCollection container = null;
  48. OciBindHandle bindHandle;
  49. #endregion // Fields
  50. #region Constructors
  51. public OracleParameter ()
  52. : this (String.Empty, OracleType.VarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
  53. {
  54. }
  55. public OracleParameter (string name, object value)
  56. {
  57. this.name = name;
  58. this.value = value;
  59. SourceVersion = DataRowVersion.Current;
  60. InferOracleType (value);
  61. }
  62. public OracleParameter (string name, OracleType dataType)
  63. : this (name, dataType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
  64. {
  65. }
  66. public OracleParameter (string name, OracleType dataType, int size)
  67. : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
  68. {
  69. }
  70. public OracleParameter (string name, OracleType dataType, int size, string srcColumn)
  71. : this (name, dataType, size, ParameterDirection.Input, false, 0, 0, srcColumn, DataRowVersion.Current, null)
  72. {
  73. }
  74. public OracleParameter (string name, OracleType dataType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string srcColumn, DataRowVersion srcVersion, object value)
  75. {
  76. this.name = name;
  77. this.size = size;
  78. this.value = value;
  79. OracleType = dataType;
  80. Direction = direction;
  81. SourceColumn = srcColumn;
  82. SourceVersion = srcVersion;
  83. }
  84. #endregion // Constructors
  85. #region Properties
  86. internal OracleParameterCollection Container {
  87. get { return container; }
  88. set { container = value; }
  89. }
  90. [Browsable (false)]
  91. [RefreshProperties (RefreshProperties.All)]
  92. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  93. public DbType DbType {
  94. get { return dbType; }
  95. set { SetDbType (value); }
  96. }
  97. [DefaultValue (ParameterDirection.Input)]
  98. [RefreshProperties (RefreshProperties.All)]
  99. public ParameterDirection Direction {
  100. get { return direction; }
  101. set { direction = value; }
  102. }
  103. [Browsable (false)]
  104. [DesignOnly (true)]
  105. [DefaultValue (false)]
  106. [EditorBrowsable (EditorBrowsableState.Never)]
  107. public bool IsNullable {
  108. get { return isNullable; }
  109. set { isNullable = value; }
  110. }
  111. [DefaultValue (0)]
  112. [Browsable (false)]
  113. public int Offset {
  114. get { return offset; }
  115. set { offset = value; }
  116. }
  117. [DefaultValue (OracleType.VarChar)]
  118. [RefreshProperties (RefreshProperties.All)]
  119. public OracleType OracleType {
  120. get { return oracleType; }
  121. set { SetOracleType (value); }
  122. }
  123. [DefaultValue ("")]
  124. public string ParameterName {
  125. get { return name; }
  126. set { name = value; }
  127. }
  128. [DefaultValue (0)]
  129. public byte Precision {
  130. get { return precision; }
  131. set { /* NO EFFECT*/ }
  132. }
  133. [DefaultValue (0)]
  134. public byte Scale {
  135. get { return scale; }
  136. set { /* NO EFFECT*/ }
  137. }
  138. [DefaultValue (0)]
  139. public int Size {
  140. get { return size; }
  141. set {
  142. sizeSet = true;
  143. size = value;
  144. }
  145. }
  146. [DefaultValue ("")]
  147. public string SourceColumn {
  148. get { return srcColumn; }
  149. set { srcColumn = value; }
  150. }
  151. [DefaultValue (DataRowVersion.Current)]
  152. public DataRowVersion SourceVersion {
  153. get { return srcVersion; }
  154. set { srcVersion = value; }
  155. }
  156. [DefaultValue (null)]
  157. [RefreshProperties (RefreshProperties.All)]
  158. [TypeConverter (typeof(StringConverter))]
  159. public object Value {
  160. get { return this.value; }
  161. set { this.value = value; }
  162. }
  163. #endregion // Properties
  164. #region Methods
  165. private void AssertSizeIsSet ()
  166. {
  167. if (!sizeSet)
  168. throw new Exception ("Size must be set.");
  169. }
  170. internal void Bind (OciStatementHandle statement, OracleConnection connection)
  171. {
  172. if (bindHandle == null)
  173. bindHandle = new OciBindHandle ((OciHandle) statement);
  174. IntPtr tmpHandle = bindHandle.Handle;
  175. if (Direction != ParameterDirection.Input)
  176. AssertSizeIsSet ();
  177. if (!sizeSet)
  178. size = InferSize ();
  179. byte[] bytes = null;
  180. int status = 0;
  181. int indicator = 0;
  182. OciDataType bindType = ociType;
  183. IntPtr bindValue = IntPtr.Zero;
  184. int bindSize = size;
  185. int rsize = 0;
  186. if (value == DBNull.Value) {
  187. indicator = 0;
  188. bindType = OciDataType.VarChar2;
  189. bindSize = 0;
  190. }
  191. else {
  192. // TODO: do other data types and oracle data types
  193. // should I be using IConvertible to convert?
  194. if (oracleType == OracleType.DateTime) {
  195. string oraDateFormat = connection.GetSessionDateFormat ();
  196. string sysDateFormat = OracleDateTime.ConvertOracleDateFormatToSystemDateTime (oraDateFormat);
  197. string sDate = "";
  198. DateTime dt = DateTime.MinValue;
  199. if (value is String) {
  200. sDate = (string) value;
  201. dt = DateTime.Parse (sDate);
  202. }
  203. else if (value is DateTime)
  204. dt = (DateTime) value;
  205. else if (value is OracleString) {
  206. sDate = (string) value;
  207. dt = DateTime.Parse (sDate);
  208. }
  209. else if (value is OracleDateTime) {
  210. OracleDateTime odt = (OracleDateTime) value;
  211. dt = (DateTime) odt.Value;
  212. }
  213. else
  214. throw new NotImplementedException (); // ?
  215. sDate = dt.ToString (sysDateFormat);
  216. rsize = 0;
  217. // Get size of buffer
  218. OciCalls.OCIUnicodeToCharSet (statement.Parent, null, sDate, out rsize);
  219. // Fill buffer
  220. bytes = new byte[rsize];
  221. OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, sDate, out rsize);
  222. bindType = OciDataType.VarChar2;
  223. //bindValue = Marshal.StringToHGlobalAnsi (sDate);
  224. bindSize = sDate.Length;
  225. }
  226. else if (oracleType == OracleType.Blob) {
  227. bytes = (byte[]) value;
  228. bindType = OciDataType.LongRaw;
  229. bindSize = bytes.Length;
  230. }
  231. else if (oracleType == OracleType.Clob) {
  232. string v = (string) value;
  233. rsize = 0;
  234. // Get size of buffer
  235. OciCalls.OCIUnicodeToCharSet (statement.Parent, null, v, out rsize);
  236. // Fill buffer
  237. bytes = new byte[rsize];
  238. OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, v, out rsize);
  239. bindType = OciDataType.Long;
  240. bindSize = bytes.Length;
  241. }
  242. else if (oracleType == OracleType.Raw) {
  243. byte[] val = value as byte[];
  244. bindValue = Marshal.AllocHGlobal (val.Length);
  245. Marshal.Copy (val, 0, bindValue, val.Length);
  246. bindSize = val.Length;
  247. }
  248. else {
  249. string svalue = value.ToString ();
  250. rsize = 0;
  251. // Get size of buffer
  252. OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
  253. // Fill buffer
  254. bytes = new byte[rsize];
  255. OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
  256. //bindValue = Marshal.StringToHGlobalAnsi (value.ToString ());
  257. bindType = OciDataType.VarChar2;
  258. bindSize = value.ToString ().Length;
  259. }
  260. }
  261. if (bytes != null) {
  262. status = OciCalls.OCIBindByNameBytes (statement,
  263. out tmpHandle,
  264. connection.ErrorHandle,
  265. ParameterName,
  266. ParameterName.Length,
  267. bytes,
  268. bindSize,
  269. bindType,
  270. indicator,
  271. IntPtr.Zero,
  272. IntPtr.Zero,
  273. 0,
  274. IntPtr.Zero,
  275. 0);
  276. }
  277. else {
  278. status = OciCalls.OCIBindByName (statement,
  279. out tmpHandle,
  280. connection.ErrorHandle,
  281. ParameterName,
  282. ParameterName.Length,
  283. bindValue,
  284. bindSize,
  285. bindType,
  286. indicator,
  287. IntPtr.Zero,
  288. IntPtr.Zero,
  289. 0,
  290. IntPtr.Zero,
  291. 0);
  292. }
  293. if (status != 0) {
  294. OciErrorInfo info = connection.ErrorHandle.HandleError ();
  295. throw new OracleException (info.ErrorCode, info.ErrorMessage);
  296. }
  297. bindHandle.SetHandle (tmpHandle);
  298. }
  299. [MonoTODO]
  300. object ICloneable.Clone ()
  301. {
  302. throw new NotImplementedException ();
  303. }
  304. private void InferOracleType (object value)
  305. {
  306. Type type = value.GetType ();
  307. string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
  308. switch (type.FullName) {
  309. case "System.Int64":
  310. SetOracleType (OracleType.Number);
  311. break;
  312. case "System.Boolean":
  313. case "System.Byte":
  314. SetOracleType (OracleType.Byte);
  315. break;
  316. case "System.String":
  317. SetOracleType (OracleType.VarChar);
  318. break;
  319. case "System.DateTime":
  320. SetOracleType (OracleType.DateTime);
  321. break;
  322. case "System.Decimal":
  323. SetOracleType (OracleType.Number);
  324. //scale = ((decimal) value).Scale;
  325. break;
  326. case "System.Double":
  327. SetOracleType (OracleType.Double);
  328. break;
  329. case "System.Byte[]":
  330. case "System.Guid":
  331. SetOracleType (OracleType.Raw);
  332. break;
  333. case "System.Int32":
  334. SetOracleType (OracleType.Int32);
  335. break;
  336. case "System.Single":
  337. SetOracleType (OracleType.Float);
  338. break;
  339. case "System.Int16":
  340. SetOracleType (OracleType.Int16);
  341. break;
  342. default:
  343. throw new ArgumentException (exception);
  344. }
  345. }
  346. [MonoTODO ("different size depending on type.")]
  347. private int InferSize ()
  348. {
  349. return value.ToString ().Length;
  350. }
  351. private void SetDbType (DbType type)
  352. {
  353. string exception = String.Format ("No mapping exists from DbType {0} to a known OracleType.", type);
  354. switch (type) {
  355. case DbType.AnsiString:
  356. oracleType = OracleType.VarChar;
  357. ociType = OciDataType.VarChar;
  358. break;
  359. case DbType.AnsiStringFixedLength:
  360. oracleType = OracleType.Char;
  361. ociType = OciDataType.Char;
  362. break;
  363. case DbType.Binary:
  364. case DbType.Guid:
  365. oracleType = OracleType.Raw;
  366. ociType = OciDataType.Raw;
  367. break;
  368. case DbType.Boolean:
  369. case DbType.Byte:
  370. oracleType = OracleType.Byte;
  371. ociType = OciDataType.Integer;
  372. break;
  373. case DbType.Currency:
  374. case DbType.Decimal:
  375. case DbType.Int64:
  376. oracleType = OracleType.Number;
  377. ociType = OciDataType.Number;
  378. break;
  379. case DbType.Date:
  380. case DbType.DateTime:
  381. case DbType.Time:
  382. oracleType = OracleType.DateTime;
  383. ociType = OciDataType.Char;
  384. break;
  385. case DbType.Double:
  386. oracleType = OracleType.Double;
  387. ociType = OciDataType.Float;
  388. break;
  389. case DbType.Int16:
  390. oracleType = OracleType.Int16;
  391. ociType = OciDataType.Integer;
  392. break;
  393. case DbType.Int32:
  394. oracleType = OracleType.Int32;
  395. ociType = OciDataType.Integer;
  396. break;
  397. case DbType.Object:
  398. oracleType = OracleType.Blob;
  399. ociType = OciDataType.Blob;
  400. break;
  401. case DbType.Single:
  402. oracleType = OracleType.Float;
  403. ociType = OciDataType.Float;
  404. break;
  405. case DbType.String:
  406. oracleType = OracleType.NVarChar;
  407. ociType = OciDataType.VarChar;
  408. break;
  409. case DbType.StringFixedLength:
  410. oracleType = OracleType.NChar;
  411. ociType = OciDataType.Char;
  412. break;
  413. default:
  414. throw new ArgumentException (exception);
  415. }
  416. dbType = type;
  417. }
  418. private void SetOracleType (OracleType type)
  419. {
  420. string exception = String.Format ("No mapping exists from OracleType {0} to a known DbType.", type);
  421. switch (type) {
  422. case OracleType.BFile:
  423. case OracleType.Blob:
  424. case OracleType.LongRaw:
  425. case OracleType.Raw:
  426. dbType = DbType.Binary;
  427. ociType = OciDataType.Raw;
  428. break;
  429. case OracleType.Byte:
  430. dbType = DbType.Byte;
  431. ociType = OciDataType.Integer;
  432. break;
  433. case OracleType.Char:
  434. dbType = DbType.AnsiStringFixedLength;
  435. ociType = OciDataType.Char;
  436. break;
  437. case OracleType.Clob:
  438. case OracleType.LongVarChar:
  439. case OracleType.RowId:
  440. case OracleType.VarChar:
  441. dbType = DbType.AnsiString;
  442. ociType = OciDataType.VarChar;
  443. break;
  444. case OracleType.Cursor:
  445. case OracleType.IntervalDayToSecond:
  446. dbType = DbType.Object;
  447. ociType = OciDataType.Blob;
  448. break;
  449. case OracleType.DateTime:
  450. case OracleType.Timestamp:
  451. case OracleType.TimestampLocal:
  452. case OracleType.TimestampWithTZ:
  453. dbType = DbType.DateTime;
  454. ociType = OciDataType.Char;
  455. break;
  456. case OracleType.Double:
  457. dbType = DbType.Double;
  458. ociType = OciDataType.Float;
  459. break;
  460. case OracleType.Float:
  461. dbType = DbType.Single;
  462. ociType = OciDataType.Float;
  463. break;
  464. case OracleType.Int16:
  465. dbType = DbType.Int16;
  466. ociType = OciDataType.Integer;
  467. break;
  468. case OracleType.Int32:
  469. case OracleType.IntervalYearToMonth:
  470. dbType = DbType.Int32;
  471. ociType = OciDataType.Integer;
  472. break;
  473. case OracleType.NChar:
  474. dbType = DbType.StringFixedLength;
  475. ociType = OciDataType.Char;
  476. break;
  477. case OracleType.NClob:
  478. case OracleType.NVarChar:
  479. dbType = DbType.String;
  480. ociType = OciDataType.VarChar;
  481. break;
  482. case OracleType.Number:
  483. dbType = DbType.VarNumeric;
  484. ociType = OciDataType.Number;
  485. break;
  486. case OracleType.SByte:
  487. dbType = DbType.SByte;
  488. ociType = OciDataType.Integer;
  489. break;
  490. case OracleType.UInt16:
  491. dbType = DbType.UInt16;
  492. ociType = OciDataType.Integer;
  493. break;
  494. case OracleType.UInt32:
  495. dbType = DbType.UInt32;
  496. ociType = OciDataType.Integer;
  497. break;
  498. default:
  499. throw new ArgumentException (exception);
  500. }
  501. oracleType = type;
  502. }
  503. public override string ToString ()
  504. {
  505. return ParameterName;
  506. }
  507. #endregion // Methods
  508. internal sealed class OracleParameterConverter : ExpandableObjectConverter
  509. {
  510. public OracleParameterConverter ()
  511. {
  512. }
  513. [MonoTODO]
  514. public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
  515. {
  516. throw new NotImplementedException ();
  517. }
  518. [MonoTODO]
  519. public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  520. {
  521. throw new NotImplementedException ();
  522. }
  523. }
  524. }
  525. }