2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="OleDbParameter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
2017-08-21 15:34:15 +00:00
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
namespace System.Data.OleDb {
using System ;
using System.ComponentModel ;
using System.Data ;
using System.Data.Common ;
using System.Data.ProviderBase ;
using System.Diagnostics ;
using System.Globalization ;
[
System . ComponentModel . TypeConverterAttribute ( typeof ( System . Data . OleDb . OleDbParameter . OleDbParameterConverter ) )
]
public sealed partial class OleDbParameter : DbParameter , ICloneable , IDbDataParameter {
private NativeDBType _metaType ;
private int _changeID ;
private string _parameterName ;
private byte _precision ;
private byte _scale ;
private bool _hasScale ;
private NativeDBType _coerceMetaType ;
public OleDbParameter ( ) : base ( ) { // V1.0 nothing
}
public OleDbParameter ( string name , object value ) : this ( ) { // MDAC 59521
Debug . Assert ( ! ( value is OleDbType ) , "use OleDbParameter(string, OleDbType)" ) ;
Debug . Assert ( ! ( value is SqlDbType ) , "use OleDbParameter(string, OleDbType)" ) ;
ParameterName = name ;
Value = value ;
}
public OleDbParameter ( string name , OleDbType dataType ) : this ( ) {
ParameterName = name ;
OleDbType = dataType ;
}
public OleDbParameter ( string name , OleDbType dataType , int size ) : this ( ) {
ParameterName = name ;
OleDbType = dataType ;
Size = size ;
}
public OleDbParameter ( string name , OleDbType dataType , int size , string srcColumn ) : this ( ) {
ParameterName = name ;
OleDbType = dataType ;
Size = size ;
SourceColumn = srcColumn ;
}
[ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508
public OleDbParameter ( string parameterName ,
OleDbType dbType , int size ,
ParameterDirection direction , Boolean isNullable ,
Byte precision , Byte scale ,
string srcColumn , DataRowVersion srcVersion ,
object value ) : this ( ) { // V1.0 everything
ParameterName = parameterName ;
OleDbType = dbType ;
Size = size ;
Direction = direction ;
IsNullable = isNullable ;
PrecisionInternal = precision ;
ScaleInternal = scale ;
SourceColumn = srcColumn ;
SourceVersion = srcVersion ;
Value = value ;
}
[ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508
public OleDbParameter ( string parameterName ,
OleDbType dbType , int size ,
ParameterDirection direction ,
Byte precision , Byte scale ,
string sourceColumn , DataRowVersion sourceVersion , bool sourceColumnNullMapping ,
object value ) : this ( ) { // V2.0 everything - round trip all browsable properties + precision/scale
ParameterName = parameterName ;
OleDbType = dbType ;
Size = size ;
Direction = direction ;
PrecisionInternal = precision ;
ScaleInternal = scale ;
SourceColumn = sourceColumn ;
SourceVersion = sourceVersion ;
SourceColumnNullMapping = sourceColumnNullMapping ;
Value = value ;
}
internal int ChangeID {
get {
return _changeID ;
}
}
override public DbType DbType {
get {
return GetBindType ( Value ) . enumDbType ;
}
set {
NativeDBType dbtype = _metaType ;
if ( ( null = = dbtype ) | | ( dbtype . enumDbType ! = value ) ) { // MDAC 63571
PropertyTypeChanging ( ) ;
_metaType = NativeDBType . FromDbType ( value ) ;
}
}
}
public override void ResetDbType ( ) {
ResetOleDbType ( ) ;
}
[
RefreshProperties ( RefreshProperties . All ) ,
ResCategoryAttribute ( Res . DataCategory_Data ) ,
ResDescriptionAttribute ( Res . OleDbParameter_OleDbType ) ,
System . Data . Common . DbProviderSpecificTypePropertyAttribute ( true ) ,
]
public OleDbType OleDbType {
get {
return GetBindType ( Value ) . enumOleDbType ;
}
set {
NativeDBType dbtype = _metaType ;
if ( ( null = = dbtype ) | | ( dbtype . enumOleDbType ! = value ) ) { // MDAC 63571
PropertyTypeChanging ( ) ;
_metaType = NativeDBType . FromDataType ( value ) ;
}
}
}
private bool ShouldSerializeOleDbType ( ) {
return ( null ! = _metaType ) ;
}
public void ResetOleDbType ( ) {
if ( null ! = _metaType ) {
PropertyTypeChanging ( ) ;
_metaType = null ;
}
}
[
ResCategoryAttribute ( Res . DataCategory_Data ) ,
ResDescriptionAttribute ( Res . DbParameter_ParameterName ) ,
]
override public string ParameterName { // V1.2.3300, XXXParameter V1.0.3300
get {
string parameterName = _parameterName ;
return ( ( null ! = parameterName ) ? parameterName : ADP . StrEmpty ) ;
}
set {
if ( _parameterName ! = value ) {
PropertyChanging ( ) ;
_parameterName = value ;
}
}
}
[DefaultValue((Byte)0)] // MDAC 65862
[ResCategoryAttribute(Res.DataCategory_Data)]
[ResDescriptionAttribute(Res.DbDataParameter_Precision)]
public new Byte Precision {
get {
return PrecisionInternal ;
}
set {
PrecisionInternal = value ;
}
}
internal byte PrecisionInternal {
get {
byte precision = _precision ;
if ( 0 = = precision ) {
precision = ValuePrecision ( Value ) ;
}
return precision ;
}
set {
if ( _precision ! = value ) {
PropertyChanging ( ) ;
_precision = value ;
}
}
}
private bool ShouldSerializePrecision ( ) {
return ( 0 ! = _precision ) ;
}
[DefaultValue((Byte)0)] // MDAC 65862
[ResCategoryAttribute(Res.DataCategory_Data)]
[ResDescriptionAttribute(Res.DbDataParameter_Scale)]
public new Byte Scale {
get {
return ScaleInternal ;
}
set {
ScaleInternal = value ;
}
}
internal byte ScaleInternal {
get {
byte scale = _scale ;
if ( ! ShouldSerializeScale ( scale ) ) { // WebData 94688
scale = ValueScale ( Value ) ;
}
return scale ;
}
set {
if ( _scale ! = value | | ! _hasScale ) {
PropertyChanging ( ) ;
_scale = value ;
_hasScale = true ;
}
}
}
private bool ShouldSerializeScale ( ) {
return ShouldSerializeScale ( _scale ) ;
}
private bool ShouldSerializeScale ( byte scale ) {
return _hasScale & & ( ( 0 ! = scale ) | | ShouldSerializePrecision ( ) ) ;
}
object ICloneable . Clone ( ) {
return new OleDbParameter ( this ) ;
}
private void CloneHelper ( OleDbParameter destination ) {
CloneHelperCore ( destination ) ;
destination . _metaType = _metaType ;
destination . _parameterName = _parameterName ;
destination . _precision = _precision ;
destination . _scale = _scale ;
destination . _hasScale = _hasScale ;
}
private void PropertyChanging ( ) {
unchecked { _changeID + + ; }
}
private void PropertyTypeChanging ( ) {
PropertyChanging ( ) ;
_coerceMetaType = null ;
CoercedValue = null ;
}
// goal: call virtual property getters only once per parameter
internal bool BindParameter ( int index , Bindings bindings ) {
int changeID = _changeID ;
object value = Value ;
NativeDBType dbtype = GetBindType ( value ) ;
if ( OleDbType . Empty = = dbtype . enumOleDbType ) {
throw ODB . UninitializedParameters ( index , dbtype . enumOleDbType ) ;
}
_coerceMetaType = dbtype ;
value = CoerceValue ( value , dbtype ) ;
CoercedValue = value ;
ParameterDirection direction = Direction ;
byte precision ;
if ( ShouldSerializePrecision ( ) ) {
precision = PrecisionInternal ;
}
else {
precision = ValuePrecision ( value ) ;
}
if ( 0 = = precision ) {
precision = dbtype . maxpre ;
}
byte scale ;
if ( ShouldSerializeScale ( ) ) {
scale = ScaleInternal ;
}
else {
scale = ValueScale ( value ) ;
}
int wtype = dbtype . wType ;
int bytecount , size ;
if ( dbtype . islong ) { // long data (image, text, ntext)
bytecount = ADP . PtrSize ;
if ( ShouldSerializeSize ( ) ) {
size = Size ;
}
else {
if ( NativeDBType . STR = = dbtype . dbType ) {
size = Int32 . MaxValue ; // WebData 98940
}
else if ( NativeDBType . WSTR = = dbtype . dbType ) {
size = Int32 . MaxValue / 2 ;
}
else {
size = Int32 . MaxValue ;
}
}
wtype | = NativeDBType . BYREF ;
}
else if ( dbtype . IsVariableLength ) { // variable length data (varbinary, varchar, nvarchar)
if ( ! ShouldSerializeSize ( ) & & ADP . IsDirection ( this , ParameterDirection . Output ) ) {
throw ADP . UninitializedParameterSize ( index , _coerceMetaType . dataType ) ;
}
bool computedSize ;
if ( ShouldSerializeSize ( ) ) {
size = Size ;
computedSize = false ;
}
else {
size = ValueSize ( value ) ;
computedSize = true ;
}
if ( 0 < size ) {
if ( NativeDBType . WSTR = = dbtype . wType ) {
// maximum 0x3FFFFFFE characters, computed this way to avoid overflow exception
bytecount = Math . Min ( size , 0x3FFFFFFE ) * 2 + 2 ;
}
else {
Debug . Assert ( NativeDBType . STR ! = dbtype . wType , "should have ANSI binding, describing is okay" ) ;
bytecount = size ;
}
if ( computedSize ) {
if ( NativeDBType . STR = = dbtype . dbType ) { // WebData 98140
// maximum 0x7ffffffe characters, computed this way to avoid overflow exception
size = Math . Min ( size , 0x3FFFFFFE ) * 2 ;
}
}
if ( ODB . LargeDataSize < bytecount ) {
bytecount = ADP . PtrSize ;
wtype | = NativeDBType . BYREF ;
}
}
else if ( 0 = = size ) {
if ( NativeDBType . WSTR = = wtype ) { // allow space for null termination character
bytecount = 2 ;
// 0 == size, okay for (STR == dbType)
}
else {
Debug . Assert ( NativeDBType . STR ! = dbtype . wType , "should have ANSI binding, describing is okay" ) ;
bytecount = 0 ;
}
}
else if ( - 1 = = size ) {
bytecount = ADP . PtrSize ;
wtype | = NativeDBType . BYREF ;
}
else {
throw ADP . InvalidSizeValue ( size ) ;
}
}
else { // fixed length data
bytecount = dbtype . fixlen ;
size = bytecount ;
}
bindings . CurrentIndex = index ;
// tagDBPARAMBINDINFO info for SetParameterInfo
bindings . DataSourceType = dbtype . dbString . DangerousGetHandle ( ) ; // NOTE: This is a constant and isn't exposed publicly, so there really isn't a potential for Handle Recycling.
bindings . Name = ADP . PtrZero ;
bindings . ParamSize = new IntPtr ( size ) ;
bindings . Flags = GetBindFlags ( direction ) ;
//bindings.Precision = precision;
//bindings.Scale = scale;
// tagDBBINDING info for CreateAccessor
bindings . Ordinal = ( IntPtr ) ( index + 1 ) ;
bindings . Part = dbtype . dbPart ;
bindings . ParamIO = GetBindDirection ( direction ) ;
bindings . Precision = precision ;
bindings . Scale = scale ;
bindings . DbType = wtype ;
bindings . MaxLen = bytecount ; // also increments databuffer size (uses DbType)
//bindings.ValueOffset = bindings.DataBufferSize; // set via MaxLen
//bindings.LengthOffset = i * sizeof_int64;
//bindings.StatusOffset = i * sizeof_int64 + sizeof_int32;
//bindings.TypeInfoPtr = 0;
//bindings.ObjectPtr = 0;
//bindings.BindExtPtr = 0;
//bindings.MemOwner = /*DBMEMOWNER_CLIENTOWNED*/0;
//bindings.Flags = 0;
//bindings.ParameterChangeID = changeID; // bind until something changes
Debug . Assert ( _changeID = = changeID , "parameter has unexpectedly changed" ) ;
if ( Bid . AdvancedOn ) {
Bid . Trace ( "<oledb.struct.tagDBPARAMBINDINFO|INFO|ADV> index=%d, parameterName='%ls'\n" , index , ParameterName ) ; //, bindings.BindInfo[index]);
Bid . Trace ( "<oledb.struct.tagDBBINDING|INFO|ADV>\n" ) ; //, bindings.DBBinding[index]);
}
return IsParameterComputed ( ) ;
}
private static object CoerceValue ( object value , NativeDBType destinationType ) {
Debug . Assert ( null ! = destinationType , "null destinationType" ) ;
if ( ( null ! = value ) & & ( DBNull . Value ! = value ) & & ( typeof ( object ) ! = destinationType . dataType ) ) {
Type currentType = value . GetType ( ) ;
if ( currentType ! = destinationType . dataType ) {
try {
if ( ( typeof ( string ) = = destinationType . dataType ) & & ( typeof ( char [ ] ) = = currentType ) ) {
}
else if ( ( NativeDBType . CY = = destinationType . dbType ) & & ( typeof ( string ) = = currentType ) ) {
value = Decimal . Parse ( ( string ) value , NumberStyles . Currency , ( IFormatProvider ) null ) ; // WebData 99376
}
else {
value = Convert . ChangeType ( value , destinationType . dataType , ( IFormatProvider ) null ) ;
}
}
catch ( Exception e ) {
//
if ( ! ADP . IsCatchableExceptionType ( e ) ) {
throw ;
}
throw ADP . ParameterConversionFailed ( value , destinationType . dataType , e ) ; // WebData 75433
}
}
}
return value ;
}
private NativeDBType GetBindType ( object value ) {
NativeDBType dbtype = _metaType ;
if ( null = = dbtype ) {
if ( ADP . IsNull ( value ) ) {
dbtype = OleDb . NativeDBType . Default ;
}
else {
dbtype = NativeDBType . FromSystemType ( value ) ;
}
}
return dbtype ;
}
internal object GetCoercedValue ( ) {
object value = CoercedValue ; // will also be set during binding, will rebind everytime if _metaType not set
if ( null = = value ) {
value = CoerceValue ( Value , _coerceMetaType ) ;
CoercedValue = value ;
}
return value ;
}
internal bool IsParameterComputed ( ) {
NativeDBType metaType = _metaType ;
return ( ( null = = metaType )
| | ( ! ShouldSerializeSize ( ) & & metaType . IsVariableLength )
| | ( ( NativeDBType . DECIMAL = = metaType . dbType ) | | ( NativeDBType . NUMERIC = = metaType . dbType )
& & ( ! ShouldSerializeScale ( ) | | ! ShouldSerializePrecision ( ) )
)
) ; // MDAC 69299
}
// @devnote: use IsParameterComputed which is called in the normal case
// only to call Prepare to throw the specialized error message
// reducing the overall number of methods to actually jit
internal void Prepare ( OleDbCommand cmd ) { // MDAC 70232
Debug . Assert ( IsParameterComputed ( ) , "Prepare computed parameter" ) ;
if ( null = = _metaType ) {
throw ADP . PrepareParameterType ( cmd ) ;
}
else if ( ! ShouldSerializeSize ( ) & & _metaType . IsVariableLength ) {
throw ADP . PrepareParameterSize ( cmd ) ;
}
else if ( ! ShouldSerializePrecision ( ) & & ! ShouldSerializeScale ( ) & & ( ( NativeDBType . DECIMAL = = _metaType . wType ) | | ( NativeDBType . NUMERIC = = _metaType . wType ) ) ) { // MDAC 71441
throw ADP . PrepareParameterScale ( cmd , _metaType . wType . ToString ( "G" , CultureInfo . InvariantCulture ) ) ;
}
// Disabling the assert, see Dev11 775862 for details: http://vstfdevdiv.redmond.corp.microsoft.com:8080/WorkItemTracking/WorkItem.aspx?artifactMoniker=775862
// Debug.Assert(false, "OleDbParameter.Prepare didn't throw");
}
[
RefreshProperties ( RefreshProperties . All ) ,
ResCategoryAttribute ( Res . DataCategory_Data ) ,
ResDescriptionAttribute ( Res . DbParameter_Value ) ,
TypeConverterAttribute ( typeof ( StringConverter ) ) ,
]
override public object Value { // V1.2.3300, XXXParameter V1.0.3300
get {
return _value ;
}
set {
_coercedValue = null ;
_value = value ;
}
}
private byte ValuePrecision ( object value ) {
return ValuePrecisionCore ( value ) ;
}
private byte ValueScale ( object value ) {
return ValueScaleCore ( value ) ;
}
private int ValueSize ( object value ) {
return ValueSizeCore ( value ) ;
}
static private int GetBindDirection ( ParameterDirection direction ) {
return ( ODB . ParameterDirectionFlag & ( int ) direction ) ;
/ * switch ( Direction ) {
default :
case ParameterDirection . Input :
return ODB . DBPARAMIO_INPUT ;
case ParameterDirection . Output :
case ParameterDirection . ReturnValue :
return ODB . DBPARAMIO_OUTPUT ;
case ParameterDirection . InputOutput :
return ( ODB . DBPARAMIO_INPUT | ODB . DBPARAMIO_OUTPUT ) ;
} * /
}
static private int GetBindFlags ( ParameterDirection direction ) {
return ( ODB . ParameterDirectionFlag & ( int ) direction ) ;
/ * switch ( Direction ) {
default :
case ParameterDirection . Input :
return ODB . DBPARAMFLAGS_ISINPUT ;
case ParameterDirection . Output :
case ParameterDirection . ReturnValue :
return ODB . DBPARAMFLAGS_ISOUTPUT ;
case ParameterDirection . InputOutput :
return ( ODB . DBPARAMFLAGS_ISINPUT | ODB . DBPARAMFLAGS_ISOUTPUT ) ;
} * /
}
// implemented as nested class to take advantage of the private/protected ShouldSerializeXXX methods
sealed internal class OleDbParameterConverter : System . ComponentModel . ExpandableObjectConverter {
// converter classes should have public ctor
public OleDbParameterConverter ( ) {
}
public override bool CanConvertTo ( ITypeDescriptorContext context , Type destinationType ) {
if ( typeof ( System . ComponentModel . Design . Serialization . InstanceDescriptor ) = = destinationType ) {
return true ;
}
return base . CanConvertTo ( context , destinationType ) ;
}
public override object ConvertTo ( ITypeDescriptorContext context , CultureInfo culture , object value , Type destinationType ) {
if ( null = = destinationType ) {
throw ADP . ArgumentNull ( "destinationType" ) ;
}
if ( ( typeof ( System . ComponentModel . Design . Serialization . InstanceDescriptor ) = = destinationType ) & & ( value is OleDbParameter ) ) {
return ConvertToInstanceDescriptor ( value as OleDbParameter ) ;
}
return base . ConvertTo ( context , culture , value , destinationType ) ;
}
private System . ComponentModel . Design . Serialization . InstanceDescriptor ConvertToInstanceDescriptor ( OleDbParameter p ) {
int flags = 0 ;
if ( p . ShouldSerializeOleDbType ( ) ) {
flags | = 1 ;
}
if ( p . ShouldSerializeSize ( ) ) {
flags | = 2 ;
}
if ( ! ADP . IsEmpty ( p . SourceColumn ) ) {
flags | = 4 ;
}
if ( null ! = p . Value ) {
flags | = 8 ;
}
if ( ( ParameterDirection . Input ! = p . Direction ) | | p . IsNullable
| | p . ShouldSerializePrecision ( ) | | p . ShouldSerializeScale ( )
| | ( DataRowVersion . Current ! = p . SourceVersion ) ) {
flags | = 16 ; // V1.0 everything
}
if ( p . SourceColumnNullMapping ) {
flags | = 32 ; // v2.0 everything
}
Type [ ] ctorParams ;
object [ ] ctorValues ;
switch ( flags ) {
case 0 : // ParameterName
case 1 : // OleDbType
ctorParams = new Type [ ] { typeof ( string ) , typeof ( OleDbType ) } ;
ctorValues = new object [ ] { p . ParameterName , p . OleDbType } ;
break ;
case 2 : // Size
case 3 : // Size, OleDbType
ctorParams = new Type [ ] { typeof ( string ) , typeof ( OleDbType ) , typeof ( int ) } ;
ctorValues = new object [ ] { p . ParameterName , p . OleDbType , p . Size } ;
break ;
case 4 : // SourceColumn
case 5 : // SourceColumn, OleDbType
case 6 : // SourceColumn, Size
case 7 : // SourceColumn, Size, OleDbType
ctorParams = new Type [ ] { typeof ( string ) , typeof ( OleDbType ) , typeof ( int ) , typeof ( string ) } ;
ctorValues = new object [ ] { p . ParameterName , p . OleDbType , p . Size , p . SourceColumn } ;
break ;
case 8 : // Value
ctorParams = new Type [ ] { typeof ( string ) , typeof ( object ) } ;
ctorValues = new object [ ] { p . ParameterName , p . Value } ;
break ;
default : // everything else
if ( 0 = = ( 32 & flags ) ) { // V1.0 everything
ctorParams = new Type [ ] {
typeof ( string ) , typeof ( OleDbType ) , typeof ( int ) , typeof ( ParameterDirection ) ,
typeof ( bool ) , typeof ( byte ) , typeof ( byte ) , typeof ( string ) ,
typeof ( DataRowVersion ) , typeof ( object ) } ;
ctorValues = new object [ ] {
p . ParameterName , p . OleDbType , p . Size , p . Direction ,
p . IsNullable , p . PrecisionInternal , p . ScaleInternal , p . SourceColumn ,
p . SourceVersion , p . Value } ;
}
else { // v2.0 everything - round trip all browsable properties + precision/scale
ctorParams = new Type [ ] {
typeof ( string ) , typeof ( OleDbType ) , typeof ( int ) , typeof ( ParameterDirection ) ,
typeof ( byte ) , typeof ( byte ) ,
typeof ( string ) , typeof ( DataRowVersion ) , typeof ( bool ) ,
typeof ( object ) } ;
ctorValues = new object [ ] {
p . ParameterName , p . OleDbType , p . Size , p . Direction ,
p . PrecisionInternal , p . ScaleInternal ,
p . SourceColumn , p . SourceVersion , p . SourceColumnNullMapping ,
p . Value } ;
}
break ;
}
System . Reflection . ConstructorInfo ctor = typeof ( OleDbParameter ) . GetConstructor ( ctorParams ) ;
return new System . ComponentModel . Design . Serialization . InstanceDescriptor ( ctor , ctorValues ) ;
}
}
}
}