/*public OdbcCommand CreateCommand() { // MDAC 68309 * OdbcCommand cmd = Connection.CreateCommand(); * cmd.Transaction = this; * return cmd; * } * * IDbCommand IDbTransaction.CreateCommand() { * return CreateCommand(); * }*/ /// <include file='doc\OdbcTransaction.uex' path='docs/doc[@for="OdbcTransaction.Commit"]/*' /> public void Commit() { OdbcConnection.OdbcPermission.Demand(); // MDAC 81476 if (null == this.connection) { throw ADP.TransactionZombied(this); } connection.CheckState(ADP.CommitTransaction); // MDAC 68289 //Note: SQLEndTran success if not actually in a transaction, so we have to throw //since the IDbTransaciton spec indicates this is an error for the managed packages if (AutoCommit) { throw ODC.NotInTransaction(); } //Commit the transaction (for just this connection) ODBC32.RETCODE retcode = (ODBC32.RETCODE) UnsafeNativeMethods.Odbc32.SQLEndTran( (short)ODBC32.SQL_HANDLE.DBC, this.connection._dbcWrapper, (Int16)ODBC32.SQL_TXN.COMMIT); if (retcode != ODBC32.RETCODE.SUCCESS) { this.connection.HandleError(this.connection._dbcWrapper, ODBC32.SQL_HANDLE.DBC, retcode); } //Transaction is complete... AutoCommit = true; this.connection.weakTransaction = null; this.connection._dbcWrapper._isInTransaction = false; this.connection = null; }
// Helpers public static OdbcErrorCollection GetDiagErrors(string source, HandleRef hrHandle, SQL_HANDLE hType, RETCODE retcode) { switch (retcode) { case RETCODE.SUCCESS: return(null); case RETCODE.INVALID_HANDLE: throw ODC.InvalidHandle(); default: { Int32 NativeError; Int16 iRec = 0; Int16 cchActual = 0; OdbcErrorCollection errors = new OdbcErrorCollection(); try { using (CNativeBuffer message = new CNativeBuffer(1024)) { using (CNativeBuffer state = new CNativeBuffer(12)) { bool moreerrors = true; while (moreerrors) { retcode = (RETCODE)UnsafeNativeMethods.Odbc32.SQLGetDiagRecW( (short)hType, hrHandle, ++iRec, //Orindals are 1:base in odbc state, out NativeError, message, (short)(message.Length / 2), //cch out cchActual); //cch //Note: SUCCESS_WITH_INFO from SQLGetDiagRec would be because //the buffer is not large enough for the error string. moreerrors = (retcode == RETCODE.SUCCESS || retcode == RETCODE.SUCCESS_WITH_INFO); if (moreerrors) { //Sets up the InnerException as well... errors.Add(new OdbcError( source, (string)message.MarshalToManaged(SQL_C.WCHAR, SQL_NTS), (string)state.MarshalToManaged(SQL_C.WCHAR, SQL_NTS), NativeError ) ); } } } } } catch { throw; } return(errors); } } }
static internal TypeMap FromSqlType(ODBC32.SQL_TYPE sqltype) { switch (sqltype) { case ODBC32.SQL_TYPE.CHAR: return(_Char); case ODBC32.SQL_TYPE.VARCHAR: return(_VarChar); case ODBC32.SQL_TYPE.LONGVARCHAR: return(_Text); case ODBC32.SQL_TYPE.WCHAR: return(_NChar); case ODBC32.SQL_TYPE.WVARCHAR: return(_NVarChar); case ODBC32.SQL_TYPE.WLONGVARCHAR: return(_NText); case ODBC32.SQL_TYPE.DECIMAL: return(_Decimal); case ODBC32.SQL_TYPE.NUMERIC: return(_Numeric); case ODBC32.SQL_TYPE.SMALLINT: return(_SmallInt); case ODBC32.SQL_TYPE.INTEGER: return(_Int); case ODBC32.SQL_TYPE.REAL: return(_Real); case ODBC32.SQL_TYPE.FLOAT: return(_Double); case ODBC32.SQL_TYPE.DOUBLE: return(_Double); case ODBC32.SQL_TYPE.BIT: return(_Bit); case ODBC32.SQL_TYPE.TINYINT: return(_TinyInt); case ODBC32.SQL_TYPE.BIGINT: return(_BigInt); case ODBC32.SQL_TYPE.BINARY: return(_Binary); case ODBC32.SQL_TYPE.VARBINARY: return(_VarBinary); case ODBC32.SQL_TYPE.LONGVARBINARY: return(_Image); case ODBC32.SQL_TYPE.TYPE_DATE: return(_Date); case ODBC32.SQL_TYPE.TYPE_TIME: return(_Time); case ODBC32.SQL_TYPE.TYPE_TIMESTAMP: return(_DateTime); case ODBC32.SQL_TYPE.GUID: return(_UniqueId); case (ODBC32.SQL_TYPE)ODBC32.SQL_SS.VARIANT: return(_Variant); default: throw ODC.UnknownSQLType(sqltype); } }
static internal TypeMap FromOdbcType(OdbcType odbcType) { switch (odbcType) { case OdbcType.BigInt: return(_BigInt); case OdbcType.Binary: return(_Binary); case OdbcType.Bit: return(_Bit); case OdbcType.Char: return(_Char); case OdbcType.DateTime: return(_DateTime); case OdbcType.Date: return(_Date); case OdbcType.Time: return(_Time); case OdbcType.Double: return(_Double); case OdbcType.Decimal: return(_Decimal); case OdbcType.Image: return(_Image); case OdbcType.Int: return(_Int); case OdbcType.NChar: return(_NChar); case OdbcType.NText: return(_NText); case OdbcType.Numeric: return(_Numeric); case OdbcType.NVarChar: return(_NVarChar); case OdbcType.Real: return(_Real); case OdbcType.UniqueIdentifier: return(_UniqueId); case OdbcType.SmallDateTime: return(_SmallDT); case OdbcType.SmallInt: return(_SmallInt); case OdbcType.Text: return(_Text); case OdbcType.Timestamp: return(_Timestamp); case OdbcType.TinyInt: return(_TinyInt); case OdbcType.VarBinary: return(_VarBinary); case OdbcType.VarChar: return(_VarChar); default: throw ODC.UnknownOdbcType(odbcType); } }
/// <include file='doc\OdbcTransaction.uex' path='docs/doc[@for="OdbcTransaction.Rollback"]/*' /> public void Rollback() { if (null == this.connection) { throw ADP.TransactionZombied(this); } connection.CheckState(ADP.RollbackTransaction); // MDAC 68289 //Note: SQLEndTran success if not actually in a transaction, so we have to throw //since the IDbTransaciton spec indicates this is an error for the managed packages if (AutoCommit) { throw ODC.NotInTransaction(); } try { // try-finally inside try-catch-throw try { //Abort the transaction (for just this connection) ODBC32.RETCODE retcode = (ODBC32.RETCODE) UnsafeNativeMethods.Odbc32.SQLEndTran( (short)ODBC32.SQL_HANDLE.DBC, this.connection._dbcWrapper, (Int16)ODBC32.SQL_TXN.ROLLBACK); if (retcode != ODBC32.RETCODE.SUCCESS) { this.connection.HandleError(this.connection._dbcWrapper, ODBC32.SQL_HANDLE.DBC, retcode); } //Transaction is complete... AutoCommit = true; } finally { this.connection.weakTransaction = null; this.connection._dbcWrapper._isInTransaction = false; this.connection = null; } } catch { // MDAC 81875 throw; } }
internal void MarshalToNative(object value, ODBC32.SQL_C sqlctype, byte precision) { IntPtr buffer = this.Ptr; switch (sqlctype) { /* #if DEBUG * case ODBC32.SQL_C.CHAR: * Debug.Assert(false, "should have bound as SQL_C.WCHAR"); * goto default; #endif */ case ODBC32.SQL_C.WCHAR: { //Note: We always bind as unicode //Note: StructureToPtr fails indicating string it a non-blittable type //and there is no MarshalStringTo* that moves to an existing buffer, //they all alloc and return a new one, not at all what we want... //So we have to copy the raw bytes of the string ourself?! Char[] rgChars = ((string)value).ToCharArray(); EnsureAlloc((rgChars.Length + 1) * 2); buffer = this.Ptr; // Realloc may have changed buffer address Marshal.Copy(rgChars, 0, buffer, rgChars.Length); Marshal.WriteInt16(buffer, rgChars.Length * 2, 0); // Add the null terminator break; } case ODBC32.SQL_C.BINARY: case ODBC32.SQL_C.CHAR: { Byte[] rgBytes = (Byte[])value; EnsureAlloc(rgBytes.Length + 1); buffer = this.Ptr; // Realloc may have changed buffer address Marshal.Copy(rgBytes, 0, buffer, rgBytes.Length); break; } case ODBC32.SQL_C.UTINYINT: Debug.Assert((Length >= 1), "Native buffer too small "); Marshal.WriteByte(buffer, (Byte)value); break; case ODBC32.SQL_C.SSHORT: //Int16 Debug.Assert((Length >= 2), "Native buffer too small "); Marshal.WriteInt16(buffer, (Int16)value); break; case ODBC32.SQL_C.SLONG: //Int32 case ODBC32.SQL_C.REAL: //float Debug.Assert((Length >= 4), "Native buffer too small "); Marshal.StructureToPtr(value, buffer, false /*deleteold*/); break; case ODBC32.SQL_C.SBIGINT: //Int64 case ODBC32.SQL_C.DOUBLE: //Double Debug.Assert((Length >= 8), "Native buffer too small "); Marshal.StructureToPtr(value, buffer, false /*deleteold*/); break; case ODBC32.SQL_C.GUID: //Guid //All of these we can just delegate Debug.Assert(16 <= Length, "Native buffer too small "); Marshal.StructureToPtr(value, buffer, false /*deleteold*/); break; case ODBC32.SQL_C.BIT: Debug.Assert((Length >= 1), "Native buffer too small "); Marshal.WriteByte(buffer, (Byte)(((bool)value) ? 1 : 0)); break; case ODBC32.SQL_C.TYPE_TIMESTAMP: { //typedef struct tagTIMESTAMP_STRUCT //{ // SQLSMALLINT year; // SQLUSMALLINT month; // SQLUSMALLINT day; // SQLUSMALLINT hour; // SQLUSMALLINT minute; // SQLUSMALLINT second; // SQLUINTEGER fraction; (billoniths of a second) //} //We have to map this ourselves, due to the different structures between //ODBC TIMESTAMP and URT DateTime, (ie: can't use StructureToPtr) Debug.Assert(16 <= Length, "Native buffer too small "); DateTime datetime = (DateTime)value; Marshal.WriteInt16(buffer, 0, (short)datetime.Year); //year Marshal.WriteInt16(buffer, 2, (short)datetime.Month); //month Marshal.WriteInt16(buffer, 4, (short)datetime.Day); //day Marshal.WriteInt16(buffer, 6, (short)datetime.Hour); //hour Marshal.WriteInt16(buffer, 8, (short)datetime.Minute); //minute Marshal.WriteInt16(buffer, 10, (short)datetime.Second); //second Marshal.WriteInt32(buffer, 12, datetime.Millisecond * 1000000); //fraction break; } // Note: System does not provide a date-only type case ODBC32.SQL_C.TYPE_DATE: { // typedef struct tagDATE_STRUCT // { // SQLSMALLINT year; // SQLUSMALLINT month; // SQLUSMALLINT day; // } DATE_STRUCT; Debug.Assert(6 <= Length, "Native buffer too small "); DateTime datetime = (DateTime)value; Marshal.WriteInt16(buffer, 0, (short)datetime.Year); //year Marshal.WriteInt16(buffer, 2, (short)datetime.Month); //month Marshal.WriteInt16(buffer, 4, (short)datetime.Day); //day break; } // Note: System does not provide a date-only type case ODBC32.SQL_C.TYPE_TIME: { // typedef struct tagTIME_STRUCT // { // SQLUSMALLINT hour; // SQLUSMALLINT minute; // SQLUSMALLINT second; // } TIME_STRUCT; Debug.Assert(6 <= Length, "Native buffer too small "); TimeSpan timespan = (TimeSpan)value; Marshal.WriteInt16(buffer, 0, (short)timespan.Hours); //hours Marshal.WriteInt16(buffer, 2, (short)timespan.Minutes); //minutes Marshal.WriteInt16(buffer, 4, (short)timespan.Seconds); //seconds break; } case ODBC32.SQL_C.NUMERIC: { //Note: Unfortunatly the ODBC NUMERIC structure and the URT DECIMAL structure do not //align, so we can't so do the typical "PtrToStructure" call (below) like other types //We actually have to go through the pain of pulling our raw bytes and building the decimal // Marshal.PtrToStructure(buffer, typeof(decimal)); //So we are mapping this ourselves //typedef struct tagSQL_NUMERIC_STRUCT //{ // SQLCHAR precision; // SQLSCHAR scale; // SQLCHAR sign; // SQLCHAR val[SQL_MAX_NUMERIC_LEN]; //} SQL_NUMERIC_STRUCT; int[] parts = Decimal.GetBits((Decimal)value); byte[] bits = BitConverter.GetBytes(parts[3]); Debug.Assert(19 <= Length, "Native buffer too small "); Marshal.WriteByte(buffer, 0, (Byte)precision); //precision Marshal.WriteByte(buffer, 1, bits[2]); //Bits 16-23 scale Marshal.WriteByte(buffer, 2, (Byte)((0 == bits[3]) ? 1 : 0)); //Bit 31 - sign(isnegative) Marshal.WriteInt32(buffer, 3, parts[0]); //val(low) Marshal.WriteInt32(buffer, 7, parts[1]); //val(mid) Marshal.WriteInt32(buffer, 11, parts[2]); //val(hi) Marshal.WriteInt32(buffer, 15, 0); //val(xhi) break; } default: throw ODC.UnknownSQLCType(sqlctype); } ; }
public object MarshalToManaged(ODBC32.SQL_C sqlctype, int cb) { IntPtr buffer = this.Ptr; switch (sqlctype) { /* #if DEBUG * case ODBC32.SQL_C.CHAR: * Debug.Assert(false, "should have bound as WCHAR"); * goto default; #endif */ case ODBC32.SQL_C.WCHAR: //Note: We always bind as unicode if (cb < 0) { String retstr = Marshal.PtrToStringUni(buffer); Debug.Assert(retstr.Length <= this.Length / 2); return(retstr); } Debug.Assert((Length >= cb), "Native buffer too small "); cb = Math.Min(cb / 2, (Length - 2) / 2); return(Marshal.PtrToStringUni(buffer, cb)); case ODBC32.SQL_C.CHAR: case ODBC32.SQL_C.BINARY: { Debug.Assert((Length >= cb), "Native buffer too small "); cb = Math.Min(cb, Length); Byte[] rgBytes = new Byte[cb]; Marshal.Copy(buffer, rgBytes, 0, cb); return(rgBytes); } case ODBC32.SQL_C.SSHORT: Debug.Assert((Length >= 2), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(Int16))); case ODBC32.SQL_C.SLONG: Debug.Assert((Length >= 4), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(int))); case ODBC32.SQL_C.SBIGINT: Debug.Assert((Length >= 8), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(Int64))); case ODBC32.SQL_C.BIT: { Debug.Assert((Length >= 1), "Native buffer too small "); Byte b = Marshal.ReadByte(buffer); return(b != 0x00); } case ODBC32.SQL_C.REAL: Debug.Assert((Length >= 8), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(float))); case ODBC32.SQL_C.DOUBLE: Debug.Assert((Length >= 8), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(double))); case ODBC32.SQL_C.UTINYINT: Debug.Assert((Length >= 1), "Native buffer too small "); return(Marshal.ReadByte(buffer)); case ODBC32.SQL_C.GUID: Debug.Assert((Length >= 16), "Native buffer too small "); return(Marshal.PtrToStructure(buffer, typeof(Guid))); case ODBC32.SQL_C.TYPE_TIMESTAMP: { //So we are mapping this ourselves. //typedef struct tagTIMESTAMP_STRUCT //{ // SQLSMALLINT year; // SQLUSMALLINT month; // SQLUSMALLINT day; // SQLUSMALLINT hour; // SQLUSMALLINT minute; // SQLUSMALLINT second; // SQLUINTEGER fraction; (billoniths of a second) //} // return (DateTime)Marshal.PtrToStructure(buffer, typeof(DateTime)); Debug.Assert(16 <= Length, "Native buffer too small "); return(new DateTime( Marshal.ReadInt16(buffer, 0), //year Marshal.ReadInt16(buffer, 2), //month Marshal.ReadInt16(buffer, 4), //day Marshal.ReadInt16(buffer, 6), //hour Marshal.ReadInt16(buffer, 8), //mintue Marshal.ReadInt16(buffer, 10), //second Marshal.ReadInt32(buffer, 12) / 1000000 //milliseconds )); } // Note: System does not provide a date-only type case ODBC32.SQL_C.TYPE_DATE: { // typedef struct tagDATE_STRUCT // { // SQLSMALLINT year; // SQLUSMALLINT month; // SQLUSMALLINT day; // } DATE_STRUCT; return(new DateTime( Marshal.ReadInt16(buffer, 0), //year Marshal.ReadInt16(buffer, 2), //month Marshal.ReadInt16(buffer, 4) //day )); } // Note: System does not provide a date-only type case ODBC32.SQL_C.TYPE_TIME: { // typedef struct tagTIME_STRUCT // { // SQLUSMALLINT hour; // SQLUSMALLINT minute; // SQLUSMALLINT second; // } TIME_STRUCT; return(new TimeSpan( Marshal.ReadInt16(buffer, 0), //hours Marshal.ReadInt16(buffer, 2), //minutes Marshal.ReadInt16(buffer, 4) //seconds )); } case ODBC32.SQL_C.NUMERIC: { //Note: Unfortunatly the ODBC NUMERIC structure and the URT DECIMAL structure do not //align, so we can't so do the typical "PtrToStructure" call (below) like other types //We actually have to go through the pain of pulling our raw bytes and building the decimal // Marshal.PtrToStructure(buffer, typeof(decimal)); //So we are mapping this ourselves //typedef struct tagSQL_NUMERIC_STRUCT //{ // SQLCHAR precision; // SQLSCHAR scale; // SQLCHAR sign; /* 1 if positive, 0 if negative */ // SQLCHAR val[SQL_MAX_NUMERIC_LEN]; //} SQL_NUMERIC_STRUCT; Debug.Assert(19 <= Length, "Native buffer too small "); return(new Decimal( Marshal.ReadInt32(buffer, 3), //val(low) Marshal.ReadInt32(buffer, 7), //val(mid) Marshal.ReadInt32(buffer, 11), //val(hi) Marshal.ReadByte(buffer, 2) == 0, //sign(isnegative) Marshal.ReadByte(buffer, 1) //scale // Marshal.ReadByte(buffer, 0), //precision )); } default: throw ODC.UnknownSQLCType(sqlctype); } ; }