2009-05-15 Veerapuram Varadhan <vvaradhan@novell.com>
[mono.git] / mcs / class / System.Data.OracleClient / System.Data.OracleClient / OracleParameter.cs
index e41828adf2f2430223ae7b22d5728cab5c567c75..a078d1cda2de4d15e4ae5666fddd82bb3482d92d 100644 (file)
@@ -123,9 +123,13 @@ namespace System.Data.OracleClient
                {
                        this.name = name;
                        this.value = value;
+                       if (value != null) {
+                               this.sizeSet = true;
+                               this.size = InferSize (value);
+                       }
                        srcColumn = string.Empty;
                        SourceVersion = DataRowVersion.Current;
-                       InferOracleType (value);
+                       InferOracleType (value);                        
                }
 
                public OracleParameter (string name, OracleType oracleType)
@@ -150,6 +154,7 @@ namespace System.Data.OracleClient
                        if (size < 0)
                                throw new ArgumentException("Size must be not be negative.");
                        this.size = size;
+                       this.sizeSet = true;
                        this.value = value;
                        SourceColumnNullMapping = sourceColumnNullMapping;
                        OracleType = oracleType;
@@ -165,6 +170,7 @@ namespace System.Data.OracleClient
                        if (size < 0)
                                throw new ArgumentException("Size must be not be negative.");
                        this.size = size;
+                       this.sizeSet = true;
                        this.value = value;
                        this.isNullable = isNullable;
                        this.precision = precision;
@@ -353,6 +359,10 @@ namespace System.Data.OracleClient
                                this.value = value;
                                if (!oracleTypeSet)
                                        InferOracleType (value);
+                               if (value != null) {
+                                       this.size = InferSize ();
+                                       this.sizeSet = true;
+                               }
                        }
                }
 
@@ -433,14 +443,23 @@ namespace System.Data.OracleClient
                                        if (direction == ParameterDirection.Input || 
                                                direction == ParameterDirection.InputOutput) {
 
-                                               svalue = v.ToString () + '\0';
+                                               svalue = v.ToString ();
+
+                                               if (direction == ParameterDirection.Input && size > 0 && svalue.Length > size)
+                                                       svalue = svalue.Substring(0, size);
+
+                                               svalue = svalue.ToString () + '\0';
                                        }
 
                                        // set bind length to size of data
-                                       bindSize = (size + 1) * 4;
+                                       //bindSize = (size + 1) * 4;
+                                       if (direction == ParameterDirection.Input)
+                                               bindSize = Encoding.UTF8.GetMaxByteCount (svalue.Length);
+                                       else
+                                               bindSize = Encoding.UTF8.GetMaxByteCount (size + 1);
 
                                        // allocate memory based on bind length
-                                       bytes = new byte[bindSize];                             
+                                       bytes = new byte [bindSize];                            
 
                                        if (direction == ParameterDirection.Input ||
                                                direction == ParameterDirection.InputOutput) {
@@ -491,6 +510,58 @@ namespace System.Data.OracleClient
                                                bytes = new byte [7];
                                        }
                                        break;
+                               case OciDataType.TimeStamp:
+                                       dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
+                                       if (dateTimeDesc == null) {
+                                               OciErrorInfo info = connection.ErrorHandle.HandleError ();
+                                               throw new OracleException (info.ErrorCode, info.ErrorMessage);
+                                       }
+                                       dateTimeDesc.ErrorHandle = connection.ErrorHandle;
+                                       bindSize = 11;
+                                       bindType = OciDataType.TimeStamp;
+                                       bindOutValue = dateTimeDesc.Handle;
+                                       bindValue = dateTimeDesc.Handle;
+                                       useRef = true;
+                                       if (direction == ParameterDirection.Input || 
+                                               direction == ParameterDirection.InputOutput) {
+
+                                               dt = DateTime.MinValue;
+                                               sDate = "";
+                                               if (isnull)
+                                                       indicator = -1;
+                                               else if (v is String) {
+                                                       sDate = (string) v;
+                                                       dt = DateTime.Parse (sDate);
+                                               }
+                                               else if (v is DateTime)
+                                                       dt = (DateTime) v;
+                                               else if (v is OracleString) {
+                                                       sDate = (string) v;
+                                                       dt = DateTime.Parse (sDate);
+                                               }
+                                               else if (v is OracleDateTime) {
+                                                       OracleDateTime odt = (OracleDateTime) v;
+                                                       dt = (DateTime) odt.Value;
+                                               }
+                                               else
+                                                       throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ?
+
+                                               short year = (short) dt.Year;
+                                               byte month = (byte) dt.Month;
+                                               byte day = (byte) dt.Day;
+                                               byte hour = (byte) dt.Hour;
+                                               byte min = (byte) dt.Minute;
+                                               byte sec = (byte) dt.Second;
+                                               uint fsec = (uint) dt.Millisecond;
+                                               string timezone = "";
+                                               dateTimeDesc.SetDateTime (connection.Session,
+                                                       connection.ErrorHandle,
+                                                       year, month, day, hour, min, sec, fsec,
+                                                       timezone);
+                                       }
+                                       break;
+                               case OciDataType.Integer:
+                               case OciDataType.Float:
                                case OciDataType.Number:
                                        bindType = OciDataType.String;
                                        indicator = 0;
@@ -522,77 +593,130 @@ namespace System.Data.OracleClient
                                                OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
                                        } 
                                        break;
-                                       case OciDataType.Long:
-                                       case OciDataType.LongVarChar:
-                                               bindType = OciDataType.LongVarChar;
+                               case OciDataType.Long:
+                               case OciDataType.LongVarChar:
+                                       bindType = OciDataType.LongVarChar;
 
-                                               // FIXME: use piecewise fetching for Long, Clob, Blob, and Long Raw
-                                               // See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci05bnd.htm#sthref724
-                                               
-                                               bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character
+                                       // FIXME: use piecewise fetching for Long, Clob, Blob, and Long Raw
+                                       // See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14250/oci05bnd.htm#sthref724
+                                       
+                                       bindSize = Size + 5; // 4 bytes prepended for length, bytes, 1 byte NUL character
 
-                                               indicator = 0;
-                                               svalue = "\0";
-                                               // convert value from managed type to type to marshal
-                                               if (direction == ParameterDirection.Input || 
-                                                       direction == ParameterDirection.InputOutput) {
+                                       indicator = 0;
+                                       svalue = "\0";
+                                       // convert value from managed type to type to marshal
+                                       if (direction == ParameterDirection.Input || 
+                                               direction == ParameterDirection.InputOutput) {
 
-                                                       svalue = v.ToString () + '\0';
-                                               }
+                                               svalue = v.ToString () + '\0';
+                                       }
 
-                                               bytes = new byte [bindSize];
-                                               // LONG is only ANSI 
-                                               ASCIIEncoding enc = new ASCIIEncoding ();
-                                               
-                                               if (direction == ParameterDirection.Input || 
-                                                       direction == ParameterDirection.InputOutput) {
-                                                       int byteCount = 0;
-                                                       if (svalue.Length > 0) {        
-                                                               byteCount = enc.GetBytes (svalue, 4, svalue.Length, bytes, 0);
-                                                               // LONG VARCHAR prepends a 4-byte length
-                                                               if (byteCount > 0) {
-                                                                       byte[] byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
-                                                                       bytes[0] = byteArrayLen[0];
-                                                                       bytes[1] = byteArrayLen[1];
-                                                                       bytes[2] = byteArrayLen[2];
-                                                                       bytes[3] = byteArrayLen[3];
-                                                               }
+                                       bytes = new byte [bindSize];
+                                       // LONG is only ANSI 
+                                       ASCIIEncoding enc = new ASCIIEncoding ();
+                                       
+                                       if (direction == ParameterDirection.Input || 
+                                               direction == ParameterDirection.InputOutput) {
+                                               int byteCount = 0;
+                                               if (svalue.Length > 0) {        
+                                                       byteCount = enc.GetBytes (svalue, 4, svalue.Length, bytes, 0);
+                                                       // LONG VARCHAR prepends a 4-byte length
+                                                       if (byteCount > 0) {
+                                                               byte[] byteArrayLen = BitConverter.GetBytes ((uint) byteCount);
+                                                               bytes[0] = byteArrayLen[0];
+                                                               bytes[1] = byteArrayLen[1];
+                                                               bytes[2] = byteArrayLen[2];
+                                                               bytes[3] = byteArrayLen[3];
                                                        }
                                                }
-                                               break;
-                                       case OciDataType.Clob:
-                                               if (direction == ParameterDirection.Input) {
-                                                       svalue = v.ToString();
-                                                       rsize = 0;
+                                       }
+                                       break;
+                               case OciDataType.Clob:
+                                       if (direction == ParameterDirection.Input) {
+                                               svalue = v.ToString();
+                                               rsize = 0;
 
-                                                       // Get size of buffer
-                                                       OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
+                                               // Get size of buffer
+                                               OciCalls.OCIUnicodeToCharSet (statement.Parent, null, svalue, out rsize);
 
-                                                       // Fill buffer
-                                                       bytes = new byte[rsize];
-                                                       OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
+                                               // Fill buffer
+                                               bytes = new byte[rsize];
+                                               OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
 
-                                                       bindType = OciDataType.Long;
+                                               bindType = OciDataType.Long;
+                                               bindSize = bytes.Length;
+                                       } 
+                                       else if (direction == ParameterDirection.InputOutput) {
+                                               // not the exact error that .net 2.0 throws, but this is better
+                                               throw new NotImplementedException ("Parameters of OracleType.Clob with direction of InputOutput are not supported.");
+                                       }
+                                       else {
+                                               // Output and Return parameters
+                                               bindSize = -1;
+                                               lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
+                                               if (lobLocator == null) {
+                                                       OciErrorInfo info = connection.ErrorHandle.HandleError ();
+                                                       throw new OracleException (info.ErrorCode, info.ErrorMessage);
+                                               }
+                                               bindOutValue = lobLocator.Handle;
+                                               bindValue = lobLocator.Handle;
+                                               lobLocator.ErrorHandle = connection.ErrorHandle;
+                                               lobLocator.Service = statement.Service;
+                                               useRef = true;
+                                       }
+                                       break;
+                               case OciDataType.Blob:
+                                       if (direction == ParameterDirection.Input) {
+                                               if (v is byte[]) {
+                                                       bytes = (byte[]) v;
+                                                       bindType = OciDataType.LongRaw;
                                                        bindSize = bytes.Length;
-                                               } 
-                                               else if (direction == ParameterDirection.InputOutput)
-                                                       // not the exact error that .net 2.0 throws, but this is better
-                                                       throw new NotImplementedException ("Parameters of OracleType.Clob with direction of InputOutput are not supported.");
-                                               else {
-                                                       // Output and Return parameters
-                                                       bindSize = -1;
+                                               }
+                                               else if (v is OracleLob) {
+                                                       OracleLob lob = (OracleLob) v;
+                                                       if (lob.LobType == OracleType.Blob) {
+                                                               lobLocator = lob.Locator;
+                                                               bindOutValue = lobLocator.Handle;
+                                                               bindValue = lobLocator.Handle;
+                                                               lobLocator.ErrorHandle = connection.ErrorHandle;
+                                                               lobLocator.Service = connection.ServiceContext;
+                                                               useRef = true;
+                                                       }
+                                                       else
+                                                               throw new NotImplementedException("For OracleType.Blob, data type OracleLob of LobType Clob/NClob is not implemented.");
+                                               }
+                                               else
+                                                       throw new NotImplementedException ("For OracleType.Blob, data type not implemented: " + v.GetType().ToString()); // ?
+                                       }
+                                       else if (direction == ParameterDirection.InputOutput) {
+                                               // not the exact error that .net 2.0 throws, but this is better
+                                               throw new NotImplementedException ("Parameters of OracleType.Blob with direction of InputOutput are not supported.");
+                                       }
+                                       else {
+                                               bindSize = -1;
+                                               if (value != null && value is OracleLob) {
+                                                       OracleLob blob = (OracleLob) value;
+                                                       if (blob.LobType == OracleType.Blob)
+                                                               if (value != OracleLob.Null) {
+                                                                       lobLocator = blob.Locator;
+                                                                       byte[] bs = (byte[]) blob.Value;
+                                                                       bindSize = bs.Length;
+                                                               }
+                                               }
+                                               if (lobLocator == null) {
                                                        lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
                                                        if (lobLocator == null) {
                                                                OciErrorInfo info = connection.ErrorHandle.HandleError ();
                                                                throw new OracleException (info.ErrorCode, info.ErrorMessage);
                                                        }
-                                                       bindOutValue = lobLocator.Handle;
-                                                       bindValue = lobLocator.Handle;
-                                                       lobLocator.ErrorHandle = connection.ErrorHandle;
-                                                       lobLocator.Service = statement.Service;
-                                                       useRef = true;
                                                }
-                                               break;
+                                               bindOutValue = lobLocator.Handle;
+                                               bindValue = lobLocator.Handle;
+                                               lobLocator.ErrorHandle = connection.ErrorHandle;
+                                               lobLocator.Service = connection.ServiceContext;
+                                               useRef = true;
+                                       }
+                                       break;
                                default:
                                        // FIXME: move this up - see how Char, Number, and Date are done...
                                        if (direction == ParameterDirection.Output || 
@@ -607,32 +731,6 @@ namespace System.Data.OracleClient
                                                        bindOutValue = OciCalls.AllocateClear (bindSize);
                                                        bindValue = bindOutValue;
                                                        break;
-                                               case OciDataType.TimeStamp:
-                                                       dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
-                                                       if (dateTimeDesc == null) {
-                                                               OciErrorInfo info = connection.ErrorHandle.HandleError ();
-                                                               throw new OracleException (info.ErrorCode, info.ErrorMessage);
-                                                       }
-                                                       dateTimeDesc.ErrorHandle = connection.ErrorHandle;
-                                                       bindSize = 11;
-                                                       bindType = OciDataType.TimeStamp;
-                                                       bindOutValue = dateTimeDesc.Handle;
-                                                       bindValue = dateTimeDesc.Handle;
-                                                       useRef = true;
-                                                       break;
-                                               case OciDataType.Blob:
-                                                       bindSize = -1;
-                                                       lobLocator = (OciLobLocator) connection.Environment.Allocate (OciHandleType.LobLocator);
-                                                       if (lobLocator == null) {
-                                                               OciErrorInfo info = connection.ErrorHandle.HandleError ();
-                                                               throw new OracleException (info.ErrorCode, info.ErrorMessage);
-                                                       }
-                                                       bindOutValue = lobLocator.Handle;
-                                                       bindValue = lobLocator.Handle;
-                                                       lobLocator.ErrorHandle = connection.ErrorHandle;
-                                                       lobLocator.Service = statement.Service;
-                                                       useRef = true;
-                                                       break;
                                                case OciDataType.RSet: // REF CURSOR
                                                        cursor = IntPtr.Zero;
                                                        OciCalls.OCIHandleAlloc (connection.Environment,
@@ -656,56 +754,7 @@ namespace System.Data.OracleClient
                                                bindSize = 0;
                                        }
                                        else {
-                                               sDate = "";
-                                               dt = DateTime.MinValue;
-                                               if (bindOracleType == OracleType.Timestamp){
-                                                       bindType = OciDataType.TimeStamp;
-                                                       bindSize = 11;
-                                                       dt = DateTime.MinValue;
-                                                       sDate = "";
-                                                       if (v is String){
-                                                               sDate = (string) v;
-                                                               dt = DateTime.Parse (sDate);
-                                                       }
-                                                       else if (v is DateTime)
-                                                               dt = (DateTime) v;
-                                                       else if (v is OracleString){
-                                                               sDate = (string) v;
-                                                               dt = DateTime.Parse (sDate);
-                                                       }
-                                                       else if (v is OracleDateTime) {
-                                                               OracleDateTime odt = (OracleDateTime) v;
-                                                               dt = (DateTime) odt.Value;
-                                                       }
-                                                       else
-                                                               throw new NotImplementedException ("For OracleType.Timestamp, data type not implemented: " + v.GetType().ToString()); // ?
-
-                                                       short year = (short) dt.Year;
-                                                       byte month = (byte) dt.Month;
-                                                       byte day = (byte) dt.Day;
-                                                       byte hour = (byte) dt.Hour;
-                                                       byte min = (byte) dt.Minute;
-                                                       byte sec = (byte) dt.Second;
-                                                       uint fsec = (uint) dt.Millisecond;
-                                                       string timezone = "";
-                                                       dateTimeDesc = (OciDateTimeDescriptor) connection.Environment.Allocate (OciHandleType.TimeStamp);
-                                                       if (dateTimeDesc == null) {
-                                                               OciErrorInfo info = connection.ErrorHandle.HandleError ();
-                                                               throw new OracleException (info.ErrorCode, info.ErrorMessage);
-                                                       }
-                                                       dateTimeDesc.ErrorHandle = connection.ErrorHandle;
-                                                       dateTimeDesc.SetDateTime (connection.Session,
-                                                               connection.ErrorHandle,
-                                                               year, month, day, hour, min, sec, fsec,
-                                                               timezone);
-                                                       useRef = true;
-                                               }
-                                               else if (bindOracleType == OracleType.Blob) {
-                                                       bytes = (byte[]) v;
-                                                       bindType = OciDataType.LongRaw;
-                                                       bindSize = bytes.Length;
-                                               }
-                                               else if (bindOracleType == OracleType.Raw) {
+                                               if (bindOracleType == OracleType.Raw) {
                                                        byte[] val = v as byte[];
                                                        bindValue = OciCalls.AllocateClear (val.Length);
                                                        Marshal.Copy (val, 0, bindValue, val.Length);
@@ -722,7 +771,7 @@ namespace System.Data.OracleClient
                                                        OciCalls.OCIUnicodeToCharSet (statement.Parent, bytes, svalue, out rsize);
 
                                                        bindType = OciDataType.String;
-                                                       bindSize = svalue.Length;
+                                                       bindSize = bytes.Length;
                                                } // else oracleType
                                        } // else - Input, Ouput...
                                        break;
@@ -826,6 +875,10 @@ namespace System.Data.OracleClient
 
                private void InferOracleType (object value)
                {
+                       // Should we throw an exception here?
+                       if (value is null)
+                               return;
+                       
                        Type type = value.GetType ();
                        string exception = String.Format ("The parameter data type of {0} is invalid.", type.FullName);
                        switch (type.FullName) {
@@ -984,7 +1037,8 @@ namespace System.Data.OracleClient
                                break;
                        case DbType.StringFixedLength:
                                oracleType = OracleType.NChar;
-                               ociType = OciDataType.Char;
+                               ociType = OciDataType.Char;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
+
                                break;
                        default:
                                throw new ArgumentException (exception);
@@ -1089,7 +1143,7 @@ namespace System.Data.OracleClient
                                throw new ArgumentException (exception);
                        }
 
-                       if (!inferring)
+                       if (!oracleTypeSet || !inferring )
                                oracleType = type;
                        bindOracleType = type;
                }
@@ -1181,9 +1235,15 @@ namespace System.Data.OracleClient
                                break;
                        case OciDataType.Blob:
                        case OciDataType.Clob:
-                               OracleLob lob = new OracleLob (lobLocator, ociType);
-                               lob.connection = connection;
-                               value = lob;
+                               if (value != null && value is OracleLob && value != OracleLob.Null) {
+                                       OracleLob lob2 = (OracleLob) value;
+                                       lob2.connection = connection;
+                               }
+                               else {
+                                       OracleLob lob = new OracleLob (lobLocator, ociType);
+                                       lob.connection = connection;
+                                       value = lob;
+                               }
                                break;
                        case OciDataType.RSet: // REF CURSOR                            
                                OciStatementHandle cursorStatement = GetOutRefCursor (cmd);