//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft // Microsoft //------------------------------------------------------------------------------ namespace System.Data.Odbc { using System; using System.Data; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.ConstrainedExecution; using System.Text; internal static class ODBC { static internal Exception ConnectionClosed() { return ADP.InvalidOperation(Res.GetString(Res.Odbc_ConnectionClosed)); } static internal Exception OpenConnectionNoOwner() { return ADP.InvalidOperation(Res.GetString(Res.Odbc_OpenConnectionNoOwner)); } static internal Exception UnknownSQLType(ODBC32.SQL_TYPE sqltype) { return ADP.Argument(Res.GetString(Res.Odbc_UnknownSQLType, sqltype.ToString())); } static internal Exception ConnectionStringTooLong() { return ADP.Argument(Res.GetString(Res.OdbcConnection_ConnectionStringTooLong, ODBC32.MAX_CONNECTION_STRING_LENGTH)); } static internal ArgumentException GetSchemaRestrictionRequired() { return ADP.Argument(Res.GetString(Res.ODBC_GetSchemaRestrictionRequired)); } static internal ArgumentOutOfRangeException NotSupportedEnumerationValue(Type type, int value) { return ADP.ArgumentOutOfRange(Res.GetString(Res.ODBC_NotSupportedEnumerationValue, type.Name, value.ToString(System.Globalization.CultureInfo.InvariantCulture)), type.Name); } static internal ArgumentOutOfRangeException NotSupportedCommandType(CommandType value) { #if DEBUG switch(value) { case CommandType.Text: case CommandType.StoredProcedure: Debug.Assert(false, "valid CommandType " + value.ToString()); break; case CommandType.TableDirect: break; default: Debug.Assert(false, "invalid CommandType " + value.ToString()); break; } #endif return ODBC.NotSupportedEnumerationValue(typeof(CommandType), (int)value); } static internal ArgumentOutOfRangeException NotSupportedIsolationLevel(IsolationLevel value) { #if DEBUG switch(value) { case IsolationLevel.Unspecified: case IsolationLevel.ReadUncommitted: case IsolationLevel.ReadCommitted: case IsolationLevel.RepeatableRead: case IsolationLevel.Serializable: case IsolationLevel.Snapshot: Debug.Assert(false, "valid IsolationLevel " + value.ToString()); break; case IsolationLevel.Chaos: break; default: Debug.Assert(false, "invalid IsolationLevel " + value.ToString()); break; } #endif return ODBC.NotSupportedEnumerationValue(typeof(IsolationLevel), (int)value); } static internal InvalidOperationException NoMappingForSqlTransactionLevel(int value) { return ADP.DataAdapter(Res.GetString(Res.Odbc_NoMappingForSqlTransactionLevel, value.ToString(CultureInfo.InvariantCulture))); } static internal Exception NegativeArgument() { return ADP.Argument(Res.GetString(Res.Odbc_NegativeArgument)); } static internal Exception CantSetPropertyOnOpenConnection() { return ADP.InvalidOperation(Res.GetString(Res.Odbc_CantSetPropertyOnOpenConnection)); } static internal Exception CantEnableConnectionpooling(ODBC32.RetCode retcode) { return ADP.DataAdapter(Res.GetString(Res.Odbc_CantEnableConnectionpooling, ODBC32.RetcodeToString(retcode))); } static internal Exception CantAllocateEnvironmentHandle(ODBC32.RetCode retcode) { return ADP.DataAdapter(Res.GetString(Res.Odbc_CantAllocateEnvironmentHandle, ODBC32.RetcodeToString(retcode))); } static internal Exception FailedToGetDescriptorHandle(ODBC32.RetCode retcode) { return ADP.DataAdapter(Res.GetString(Res.Odbc_FailedToGetDescriptorHandle, ODBC32.RetcodeToString(retcode))); } static internal Exception NotInTransaction() { return ADP.InvalidOperation(Res.GetString(Res.Odbc_NotInTransaction)); } static internal Exception UnknownOdbcType(OdbcType odbctype) { return ADP.InvalidEnumerationValue(typeof(OdbcType), (int) odbctype); } internal const string Pwd = "pwd"; static internal void TraceODBC(int level, string method, ODBC32.RetCode retcode) { Bid.TraceSqlReturn(" %08X{SQLRETURN}, method=%ls\n", retcode, method); } internal static short ShortStringLength(string inputString) { return checked((short)ADP.StringLength(inputString)); } } internal static class ODBC32 { internal enum SQL_HANDLE : short { ENV = 1, DBC = 2, STMT = 3, DESC = 4, } // from .\public\sdk\inc\sqlext.h: and .\public\sdk\inc\sql.h // must be public because it is serialized by OdbcException [Serializable] public enum RETCODE : int { // must be int instead of short for Everett OdbcException Serializablity. SUCCESS = 0, SUCCESS_WITH_INFO = 1, ERROR = -1, INVALID_HANDLE = -2, NO_DATA = 100, } // must be public because it is serialized by OdbcException internal enum RetCode : short { SUCCESS = 0, SUCCESS_WITH_INFO = 1, ERROR = -1, INVALID_HANDLE = -2, NO_DATA = 100, } internal static string RetcodeToString(RetCode retcode) { switch (retcode) { case RetCode.SUCCESS: return "SUCCESS"; case RetCode.SUCCESS_WITH_INFO: return "SUCCESS_WITH_INFO"; case RetCode.ERROR: return "ERROR"; case RetCode.INVALID_HANDLE: return "INVALID_HANDLE"; case RetCode.NO_DATA: return "NO_DATA"; default: Debug.Assert(false, "Unknown enumerator passed to RetcodeToString method"); goto case RetCode.ERROR; } } internal enum SQL_CONVERT : ushort { BIGINT = 53, BINARY = 54, BIT = 55, CHAR = 56, DATE = 57, DECIMAL = 58, DOUBLE = 59, FLOAT = 60, INTEGER = 61, LONGVARCHAR = 62, NUMERIC = 63, REAL = 64, SMALLINT = 65, TIME = 66, TIMESTAMP = 67, TINYINT = 68, VARBINARY = 69, VARCHAR = 70, LONGVARBINARY = 71, } [Flags] internal enum SQL_CVT { CHAR = 0x00000001, NUMERIC = 0x00000002, DECIMAL = 0x00000004, INTEGER = 0x00000008, SMALLINT = 0x00000010, FLOAT = 0x00000020, REAL = 0x00000040, DOUBLE = 0x00000080, VARCHAR = 0x00000100, LONGVARCHAR = 0x00000200, BINARY = 0x00000400, VARBINARY = 0x00000800, BIT = 0x00001000, TINYINT = 0x00002000, BIGINT = 0x00004000, DATE = 0x00008000, TIME = 0x00010000, TIMESTAMP = 0x00020000, LONGVARBINARY = 0x00040000, INTERVAL_YEAR_MONTH = 0x00080000, INTERVAL_DAY_TIME = 0x00100000, WCHAR = 0x00200000, WLONGVARCHAR = 0x00400000, WVARCHAR = 0x00800000, GUID = 0x01000000, } internal enum STMT : short { CLOSE = 0, DROP = 1, UNBIND = 2, RESET_PARAMS = 3, } internal enum SQL_MAX{ NUMERIC_LEN = 16, } internal enum SQL_IS{ POINTER = -4, INTEGER = -6, UINTEGER = -5, SMALLINT = -8, } //SQL Server specific defines // internal enum SQL_HC // from Odbcss.h { OFF = 0, // FOR BROWSE columns are hidden ON = 1, // FOR BROWSE columns are exposed } internal enum SQL_NB // from Odbcss.h { OFF = 0, // NO_BROWSETABLE is off ON = 1, // NO_BROWSETABLE is on } // SQLColAttributes driver specific defines. // SQLSet/GetDescField driver specific defines. // Microsoft has 1200 thru 1249 reserved for Microsoft SQL Server driver usage. // internal enum SQL_CA_SS // from Odbcss.h { BASE = 1200, // SQL_CA_SS_BASE COLUMN_HIDDEN = BASE + 11, // Column is hidden (FOR BROWSE) COLUMN_KEY = BASE + 12, // Column is key column (FOR BROWSE) VARIANT_TYPE = BASE + 15, VARIANT_SQL_TYPE = BASE + 16, VARIANT_SERVER_TYPE = BASE + 17, } internal enum SQL_SOPT_SS // from Odbcss.h { BASE = 1225, // SQL_SOPT_SS_BASE HIDDEN_COLUMNS = BASE + 2, // Expose FOR BROWSE hidden columns NOBROWSETABLE = BASE + 3, // Set NOBROWSETABLE option } internal const Int16 SQL_COMMIT = 0; //Commit internal const Int16 SQL_ROLLBACK = 1; //Abort static internal readonly IntPtr SQL_AUTOCOMMIT_OFF = ADP.PtrZero; static internal readonly IntPtr SQL_AUTOCOMMIT_ON = new IntPtr(1); internal enum SQL_TRANSACTION { READ_UNCOMMITTED = 0x00000001, READ_COMMITTED = 0x00000002, REPEATABLE_READ = 0x00000004, SERIALIZABLE = 0x00000008, SNAPSHOT = 0x00000020, // VSDD 414121: SQL_TXN_SS_SNAPSHOT == 0x20 (sqlncli.h) } internal enum SQL_PARAM { // unused TYPE_UNKNOWN = 0, // SQL_PARAM_TYPE_UNKNOWN INPUT = 1, // SQL_PARAM_INPUT INPUT_OUTPUT = 2, // SQL_PARAM_INPUT_OUTPUT // unused RESULT_COL = 3, // SQL_RESULT_COL OUTPUT = 4, // SQL_PARAM_OUTPUT RETURN_VALUE = 5, // SQL_RETURN_VALUE } // SQL_API_* values // there are a gillion of these I am only defining the ones currently needed // others can be added as needed internal enum SQL_API : ushort { SQLCOLUMNS = 40, SQLEXECDIRECT = 11, SQLGETTYPEINFO = 47, SQLPROCEDURECOLUMNS = 66, SQLPROCEDURES = 67, SQLSTATISTICS = 53, SQLTABLES = 54, } internal enum SQL_DESC : short { // from sql.h (ODBCVER >= 3.0) // COUNT = 1001, TYPE = 1002, LENGTH = 1003, OCTET_LENGTH_PTR = 1004, PRECISION = 1005, SCALE = 1006, DATETIME_INTERVAL_CODE = 1007, NULLABLE = 1008, INDICATOR_PTR = 1009, DATA_PTR = 1010, NAME = 1011, UNNAMED = 1012, OCTET_LENGTH = 1013, ALLOC_TYPE = 1099, // from sqlext.h (ODBCVER >= 3.0) // CONCISE_TYPE = SQL_COLUMN.TYPE, DISPLAY_SIZE = SQL_COLUMN.DISPLAY_SIZE, UNSIGNED = SQL_COLUMN.UNSIGNED, UPDATABLE = SQL_COLUMN.UPDATABLE, AUTO_UNIQUE_VALUE = SQL_COLUMN.AUTO_INCREMENT, TYPE_NAME = SQL_COLUMN.TYPE_NAME, TABLE_NAME = SQL_COLUMN.TABLE_NAME, SCHEMA_NAME = SQL_COLUMN.OWNER_NAME, CATALOG_NAME = SQL_COLUMN.QUALIFIER_NAME, BASE_COLUMN_NAME = 22, BASE_TABLE_NAME = 23, } // ODBC version 2.0 style attributes // All IdentifierValues are ODBC 1.0 unless marked differently // internal enum SQL_COLUMN { COUNT = 0, NAME = 1, TYPE = 2, LENGTH = 3, PRECISION = 4, SCALE = 5, DISPLAY_SIZE = 6, NULLABLE = 7, UNSIGNED = 8, MONEY = 9, UPDATABLE = 10, AUTO_INCREMENT = 11, CASE_SENSITIVE = 12, SEARCHABLE = 13, TYPE_NAME = 14, TABLE_NAME = 15, // (ODBC 2.0) OWNER_NAME = 16, // (ODBC 2.0) QUALIFIER_NAME = 17, // (ODBC 2.0) LABEL = 18, } internal enum SQL_GROUP_BY { NOT_SUPPORTED = 0, // SQL_GB_NOT_SUPPORTED GROUP_BY_EQUALS_SELECT = 1, // SQL_GB_GROUP_BY_EQUALS_SELECT GROUP_BY_CONTAINS_SELECT = 2, // SQL_GB_GROUP_BY_CONTAINS_SELECT NO_RELATION = 3, // SQL_GB_NO_RELATION COLLATE = 4, // SQL_GB_COLLATE - added in ODBC 3.0 } // values from sqlext.h internal enum SQL_SQL92_RELATIONAL_JOIN_OPERATORS { CORRESPONDING_CLAUSE = 0x00000001, // SQL_SRJO_CORRESPONDING_CLAUSE CROSS_JOIN = 0x00000002, // SQL_SRJO_CROSS_JOIN EXCEPT_JOIN = 0x00000004, // SQL_SRJO_EXCEPT_JOIN FULL_OUTER_JOIN = 0x00000008, // SQL_SRJO_FULL_OUTER_JOIN INNER_JOIN = 0x00000010, // SQL_SRJO_INNER_JOIN INTERSECT_JOIN = 0x00000020, // SQL_SRJO_INTERSECT_JOIN LEFT_OUTER_JOIN = 0x00000040, // SQL_SRJO_LEFT_OUTER_JOIN NATURAL_JOIN = 0x00000080, // SQL_SRJO_NATURAL_JOIN RIGHT_OUTER_JOIN = 0x00000100, // SQL_SRJO_RIGHT_OUTER_JOIN UNION_JOIN = 0x00000200, // SQL_SRJO_UNION_JOIN } // values from sql.h internal enum SQL_OJ_CAPABILITIES { LEFT = 0x00000001, // SQL_OJ_LEFT RIGHT = 0x00000002, // SQL_OJ_RIGHT FULL = 0x00000004, // SQL_OJ_FULL NESTED = 0x00000008, // SQL_OJ_NESTED NOT_ORDERED = 0x00000010, // SQL_OJ_NOT_ORDERED INNER = 0x00000020, // SQL_OJ_INNER ALL_COMPARISON_OPS = 0x00000040, //SQL_OJ_ALLCOMPARISION+OPS } internal enum SQL_UPDATABLE { READONLY = 0, // SQL_ATTR_READ_ONLY WRITE = 1, // SQL_ATTR_WRITE READWRITE_UNKNOWN = 2, // SQL_ATTR_READWRITE_UNKNOWN } internal enum SQL_IDENTIFIER_CASE { UPPER = 1, // SQL_IC_UPPER LOWER = 2, // SQL_IC_LOWER SENSITIVE = 3, // SQL_IC_SENSITIVE MIXED = 4, // SQL_IC_MIXED } // Uniqueness parameter in the SQLStatistics function internal enum SQL_INDEX : short { UNIQUE = 0, ALL = 1, } // Reserved parameter in the SQLStatistics function internal enum SQL_STATISTICS_RESERVED : short { QUICK = 0, // SQL_QUICK ENSURE = 1, // SQL_ENSURE } // Identifier type parameter in the SQLSpecialColumns function internal enum SQL_SPECIALCOLS : ushort { BEST_ROWID = 1, // SQL_BEST_ROWID ROWVER = 2, // SQL_ROWVER } // Scope parameter in the SQLSpecialColumns function internal enum SQL_SCOPE : ushort { CURROW = 0, // SQL_SCOPE_CURROW TRANSACTION = 1, // SQL_SCOPE_TRANSACTION SESSION = 2, // SQL_SCOPE_SESSION } internal enum SQL_NULLABILITY : ushort { NO_NULLS = 0, // SQL_NO_NULLS NULLABLE = 1, // SQL_NULLABLE UNKNOWN = 2, // SQL_NULLABLE_UNKNOWN } internal enum SQL_SEARCHABLE { UNSEARCHABLE = 0, // SQL_UNSEARCHABLE LIKE_ONLY = 1, // SQL_LIKE_ONLY ALL_EXCEPT_LIKE = 2, // SQL_ALL_EXCEPT_LIKE SEARCHABLE = 3, // SQL_SEARCHABLE } internal enum SQL_UNNAMED { NAMED = 0, // SQL_NAMED UNNAMED = 1, // SQL_UNNAMED } // todo:move // internal constants // not odbc specific // internal enum HANDLER { IGNORE = 0x00000000, THROW = 0x00000001, } // values for SQLStatistics TYPE column internal enum SQL_STATISTICSTYPE { TABLE_STAT = 0, // TABLE Statistics INDEX_CLUSTERED = 1, // CLUSTERED index statistics INDEX_HASHED = 2, // HASHED index statistics INDEX_OTHER = 3, // OTHER index statistics } // values for SQLProcedures PROCEDURE_TYPE column internal enum SQL_PROCEDURETYPE { UNKNOWN = 0, // procedure is of unknow type PROCEDURE = 1, // procedure is a procedure FUNCTION = 2, // procedure is a function } // private constants // to define data types (see below) // private const Int32 SIGNED_OFFSET = -20; // SQL_SIGNED_OFFSET private const Int32 UNSIGNED_OFFSET = -22; // SQL_UNSIGNED_OFFSET //C Data Types - used when getting data (SQLGetData) internal enum SQL_C : short { CHAR = 1, //SQL_C_CHAR WCHAR = -8, //SQL_C_WCHAR SLONG = 4 + SIGNED_OFFSET, //SQL_C_LONG+SQL_SIGNED_OFFSET // ULONG = 4 + UNSIGNED_OFFSET, //SQL_C_LONG+SQL_UNSIGNED_OFFSET SSHORT = 5 + SIGNED_OFFSET, //SQL_C_SSHORT+SQL_SIGNED_OFFSET // USHORT = 5 + UNSIGNED_OFFSET, //SQL_C_USHORT+SQL_UNSIGNED_OFFSET REAL = 7, //SQL_C_REAL DOUBLE = 8, //SQL_C_DOUBLE BIT = -7, //SQL_C_BIT // STINYINT = -6 + SIGNED_OFFSET, //SQL_C_STINYINT+SQL_SIGNED_OFFSET UTINYINT = -6 + UNSIGNED_OFFSET, //SQL_C_UTINYINT+SQL_UNSIGNED_OFFSET SBIGINT = -5 + SIGNED_OFFSET, //SQL_C_SBIGINT+SQL_SIGNED_OFFSET UBIGINT = -5 + UNSIGNED_OFFSET, //SQL_C_UBIGINT+SQL_UNSIGNED_OFFSET BINARY = -2, //SQL_C_BINARY TIMESTAMP = 11, //SQL_C_TIMESTAMP TYPE_DATE = 91, //SQL_C_TYPE_DATE TYPE_TIME = 92, //SQL_C_TYPE_TIME TYPE_TIMESTAMP = 93, //SQL_C_TYPE_TIMESTAMP NUMERIC = 2, //SQL_C_NUMERIC GUID = -11, //SQL_C_GUID DEFAULT = 99, //SQL_C_DEFAULT ARD_TYPE = -99, //SQL_ARD_TYPE } //SQL Data Types - returned as column types (SQLColAttribute) internal enum SQL_TYPE : short { CHAR = SQL_C.CHAR, //SQL_CHAR VARCHAR = 12, //SQL_VARCHAR LONGVARCHAR = -1, //SQL_LONGVARCHAR WCHAR = SQL_C.WCHAR, //SQL_WCHAR WVARCHAR = -9, //SQL_WVARCHAR WLONGVARCHAR = -10, //SQL_WLONGVARCHAR DECIMAL = 3, //SQL_DECIMAL NUMERIC = SQL_C.NUMERIC, //SQL_NUMERIC SMALLINT = 5, //SQL_SMALLINT INTEGER = 4, //SQL_INTEGER REAL = SQL_C.REAL, //SQL_REAL FLOAT = 6, //SQL_FLOAT DOUBLE = SQL_C.DOUBLE, //SQL_DOUBLE BIT = SQL_C.BIT, //SQL_BIT TINYINT = -6, //SQL_TINYINT BIGINT = -5, //SQL_BIGINT BINARY = SQL_C.BINARY, //SQL_BINARY VARBINARY = -3, //SQL_VARBINARY LONGVARBINARY = -4, //SQL_LONGVARBINARY // DATE = 9, //SQL_DATE TYPE_DATE = SQL_C.TYPE_DATE, //SQL_TYPE_DATE TYPE_TIME = SQL_C.TYPE_TIME, //SQL_TYPE_TIME TIMESTAMP = SQL_C.TIMESTAMP, //SQL_TIMESTAMP TYPE_TIMESTAMP = SQL_C.TYPE_TIMESTAMP, //SQL_TYPE_TIMESTAMP GUID = SQL_C.GUID, //SQL_GUID // from odbcss.h in mdac 9.0 sources! // Driver specific SQL type defines. // Microsoft has -150 thru -199 reserved for Microsoft SQL Server driver usage. // SS_VARIANT = -150, SS_UDT = -151, SS_XML = -152, SS_UTCDATETIME = -153, SS_TIME_EX = -154, } internal const Int16 SQL_ALL_TYPES = 0; static internal readonly IntPtr SQL_HANDLE_NULL = ADP.PtrZero; internal const Int32 SQL_NULL_DATA = -1; // sql.h internal const Int32 SQL_NO_TOTAL = -4; // sqlext.h internal const Int32 SQL_DEFAULT_PARAM= -5; // internal const Int32 SQL_IGNORE = -6; // column ordinals for SQLProcedureColumns result set // this column ordinals are not defined in any c/c++ header but in the ODBC Programmer's Reference under SQLProcedureColumns // internal const Int32 COLUMN_NAME = 4; internal const Int32 COLUMN_TYPE = 5; internal const Int32 DATA_TYPE = 6; internal const Int32 COLUMN_SIZE = 8; internal const Int32 DECIMAL_DIGITS = 10; internal const Int32 NUM_PREC_RADIX = 11; internal enum SQL_ATTR { APP_ROW_DESC = 10010, // (ODBC 3.0) APP_PARAM_DESC = 10011, // (ODBC 3.0) IMP_ROW_DESC = 10012, // (ODBC 3.0) IMP_PARAM_DESC = 10013, // (ODBC 3.0) METADATA_ID = 10014, // (ODBC 3.0) ODBC_VERSION = 200, CONNECTION_POOLING = 201, AUTOCOMMIT = 102, TXN_ISOLATION = 108, CURRENT_CATALOG = 109, LOGIN_TIMEOUT = 103, QUERY_TIMEOUT = 0, // from sqlext.h CONNECTION_DEAD = 1209, // from sqlext.h // from sqlncli.h SQL_COPT_SS_BASE = 1200, SQL_COPT_SS_ENLIST_IN_DTC = (SQL_COPT_SS_BASE + 7), SQL_COPT_SS_TXN_ISOLATION = (SQL_COPT_SS_BASE + 27), // Used to set/get any driver-specific or ODBC-defined TXN iso level } //SQLGetInfo internal enum SQL_INFO : ushort { DATA_SOURCE_NAME = 2, // SQL_DATA_SOURCE_NAME in sql.h SERVER_NAME = 13, // SQL_SERVER_NAME in sql.h DRIVER_NAME = 6, // SQL_DRIVER_NAME as defined in sqlext.h DRIVER_VER = 7, // SQL_DRIVER_VER as defined in sqlext.h ODBC_VER = 10, // SQL_ODBC_VER as defined in sqlext.h SEARCH_PATTERN_ESCAPE = 14, // SQL_SEARCH_PATTERN_ESCAPE from sql.h DBMS_VER = 18, DBMS_NAME = 17, // SQL_DBMS_NAME as defined in sqlext.h IDENTIFIER_CASE = 28, // SQL_IDENTIFIER_CASE from sql.h IDENTIFIER_QUOTE_CHAR = 29, // SQL_IDENTIFIER_QUOTE_CHAR from sql.h CATALOG_NAME_SEPARATOR = 41, // SQL_CATALOG_NAME_SEPARATOR DRIVER_ODBC_VER = 77, // SQL_DRIVER_ODBC_VER as defined in sqlext.h GROUP_BY = 88, // SQL_GROUP_BY as defined in sqlext.h KEYWORDS = 89, // SQL_KEYWORDS as defined in sqlext.h ORDER_BY_COLUMNS_IN_SELECT = 90, // SQL_ORDER_BY_COLUNS_IN_SELECT in sql.h QUOTED_IDENTIFIER_CASE = 93, // SQL_QUOTED_IDENTIFIER_CASE in sqlext.h SQL_OJ_CAPABILITIES_30 = 115, //SQL_OJ_CAPABILITIES from sql.h SQL_OJ_CAPABILITIES_20 = 65003, //SQL_OJ_CAPABILITIES from sqlext.h SQL_SQL92_RELATIONAL_JOIN_OPERATORS = 161, //SQL_SQL92_RELATIONAL_JOIN_OPERATORS from sqlext.h } static internal readonly IntPtr SQL_OV_ODBC3 = new IntPtr(3); internal const Int32 SQL_NTS = -3; //flags for null-terminated string //Pooling static internal readonly IntPtr SQL_CP_OFF = new IntPtr(0); //Connection Pooling disabled static internal readonly IntPtr SQL_CP_ONE_PER_DRIVER = new IntPtr(1); //One pool per driver static internal readonly IntPtr SQL_CP_ONE_PER_HENV = new IntPtr(2); //One pool per environment /* values for SQL_ATTR_CONNECTION_DEAD */ internal const Int32 SQL_CD_TRUE = 1; internal const Int32 SQL_CD_FALSE = 0; internal const Int32 SQL_DTC_DONE = 0; internal const Int32 SQL_IS_POINTER = -4; internal const Int32 SQL_IS_PTR = 1; internal enum SQL_DRIVER { NOPROMPT = 0, COMPLETE = 1, PROMPT = 2, COMPLETE_REQUIRED = 3, } // todo:move // internal const. not odbc specific // // Connection string max length internal const Int32 MAX_CONNECTION_STRING_LENGTH = 1024; // Column set for SQLPrimaryKeys internal enum SQL_PRIMARYKEYS : short { /* CATALOGNAME = 1, // TABLE_CAT SCHEMANAME = 2, // TABLE_SCHEM TABLENAME = 3, // TABLE_NAME */ COLUMNNAME = 4, // COLUMN_NAME /* KEY_SEQ = 5, // KEY_SEQ PKNAME = 6, // PK_NAME */ } // Column set for SQLStatistics internal enum SQL_STATISTICS : short { /* CATALOGNAME = 1, // TABLE_CAT SCHEMANAME = 2, // TABLE_SCHEM TABLENAME = 3, // TABLE_NAME NONUNIQUE = 4, // NON_UNIQUE INDEXQUALIFIER = 5, // INDEX_QUALIFIER */ INDEXNAME = 6, // INDEX_NAME /* TYPE = 7, // TYPE */ ORDINAL_POSITION = 8, // ORDINAL_POSITION COLUMN_NAME = 9, // COLUMN_NAME /* ASC_OR_DESC = 10, // ASC_OR_DESC CARDINALITY = 11, // CARDINALITY PAGES = 12, // PAGES FILTER_CONDITION = 13, // FILTER_CONDITION */ } // Column set for SQLSpecialColumns internal enum SQL_SPECIALCOLUMNSET : short { /* SCOPE = 1, // SCOPE */ COLUMN_NAME = 2, // COLUMN_NAME /* DATA_TYPE = 3, // DATA_TYPE TYPE_NAME = 4, // TYPE_NAME COLUMN_SIZE = 5, // COLUMN_SIZE BUFFER_LENGTH = 6, // BUFFER_LENGTH DECIMAL_DIGITS = 7, // DECIMAL_DIGITS PSEUDO_COLUMN = 8, // PSEUDO_COLUMN */ } internal const short SQL_DIAG_SQLSTATE = 4; internal const short SQL_RESULT_COL = 3; // Helpers static internal OdbcErrorCollection GetDiagErrors(string source, OdbcHandle hrHandle, RetCode retcode) { OdbcErrorCollection errors = new OdbcErrorCollection(); GetDiagErrors(errors, source, hrHandle, retcode); return errors; } static internal void GetDiagErrors(OdbcErrorCollection errors, string source, OdbcHandle hrHandle, RetCode retcode) { Debug.Assert(retcode!=ODBC32.RetCode.INVALID_HANDLE, "retcode must never be ODBC32.RetCode.INVALID_HANDLE"); if (RetCode.SUCCESS != retcode) { Int32 NativeError; Int16 iRec = 0; Int16 cchActual = 0; StringBuilder message = new StringBuilder(1024); string sqlState; bool moreerrors = true; while(moreerrors) { ++iRec; retcode = hrHandle.GetDiagnosticRecord(iRec, out sqlState, message, out NativeError, out cchActual); if ((RetCode.SUCCESS_WITH_INFO == retcode) && (message.Capacity-1 < cchActual)) { message.Capacity = cchActual+1; retcode = hrHandle.GetDiagnosticRecord(iRec, out sqlState, message, out NativeError, out cchActual); } //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, message.ToString(), sqlState, NativeError ) ); } } } } } sealed internal class TypeMap { // MDAC 68988 // private TypeMap (OdbcType odbcType, DbType dbType, Type type, ODBC32.SQL_TYPE sql_type, ODBC32.SQL_C sql_c, ODBC32.SQL_C param_sql_c, int bsize, int csize, bool signType) // --------------- ------------------ -------------- ---------- ------------------------- ------------------- ------------------------- ----------------------- static private readonly TypeMap _BigInt = new TypeMap(OdbcType.BigInt, DbType.Int64, typeof(Int64), ODBC32.SQL_TYPE.BIGINT, ODBC32.SQL_C.SBIGINT, ODBC32.SQL_C.SBIGINT, 8, 20, true); static private readonly TypeMap _Binary = new TypeMap(OdbcType.Binary, DbType.Binary, typeof(byte[]), ODBC32.SQL_TYPE.BINARY, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static private readonly TypeMap _Bit = new TypeMap(OdbcType.Bit, DbType.Boolean, typeof(Boolean), ODBC32.SQL_TYPE.BIT, ODBC32.SQL_C.BIT, ODBC32.SQL_C.BIT, 1, 1, false); static internal readonly TypeMap _Char = new TypeMap(OdbcType.Char, DbType.AnsiStringFixedLength, typeof(String), ODBC32.SQL_TYPE.CHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.CHAR, -1, -1, false); static private readonly TypeMap _DateTime = new TypeMap(OdbcType.DateTime, DbType.DateTime, typeof(DateTime), ODBC32.SQL_TYPE.TYPE_TIMESTAMP, ODBC32.SQL_C.TYPE_TIMESTAMP, ODBC32.SQL_C.TYPE_TIMESTAMP, 16, 23, false); static private readonly TypeMap _Date = new TypeMap(OdbcType.Date, DbType.Date, typeof(DateTime), ODBC32.SQL_TYPE.TYPE_DATE, ODBC32.SQL_C.TYPE_DATE, ODBC32.SQL_C.TYPE_DATE, 6, 10, false); static private readonly TypeMap _Time = new TypeMap(OdbcType.Time, DbType.Time, typeof(TimeSpan), ODBC32.SQL_TYPE.TYPE_TIME, ODBC32.SQL_C.TYPE_TIME, ODBC32.SQL_C.TYPE_TIME, 6, 12, false); static private readonly TypeMap _Decimal = new TypeMap(OdbcType.Decimal, DbType.Decimal, typeof(Decimal), ODBC32.SQL_TYPE.DECIMAL, ODBC32.SQL_C.NUMERIC, ODBC32.SQL_C.NUMERIC, 19, ADP.DecimalMaxPrecision28, false); // static private readonly TypeMap _Currency = new TypeMap(OdbcType.Decimal, DbType.Currency, typeof(Decimal), ODBC32.SQL_TYPE.DECIMAL, ODBC32.SQL_C.NUMERIC, ODBC32.SQL_C.NUMERIC, 19, ADP.DecimalMaxPrecision28, false); static private readonly TypeMap _Double = new TypeMap(OdbcType.Double, DbType.Double, typeof(Double), ODBC32.SQL_TYPE.DOUBLE, ODBC32.SQL_C.DOUBLE, ODBC32.SQL_C.DOUBLE, 8, 15, false); static internal readonly TypeMap _Image = new TypeMap(OdbcType.Image, DbType.Binary, typeof(Byte[]), ODBC32.SQL_TYPE.LONGVARBINARY, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static private readonly TypeMap _Int = new TypeMap(OdbcType.Int, DbType.Int32, typeof(Int32), ODBC32.SQL_TYPE.INTEGER, ODBC32.SQL_C.SLONG, ODBC32.SQL_C.SLONG, 4, 10, true); static private readonly TypeMap _NChar = new TypeMap(OdbcType.NChar, DbType.StringFixedLength, typeof(String), ODBC32.SQL_TYPE.WCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.WCHAR, -1, -1, false); static internal readonly TypeMap _NText = new TypeMap(OdbcType.NText, DbType.String, typeof(String), ODBC32.SQL_TYPE.WLONGVARCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.WCHAR, -1, -1, false); static private readonly TypeMap _Numeric = new TypeMap(OdbcType.Numeric, DbType.Decimal, typeof(Decimal), ODBC32.SQL_TYPE.NUMERIC, ODBC32.SQL_C.NUMERIC, ODBC32.SQL_C.NUMERIC, 19, ADP.DecimalMaxPrecision28, false); static internal readonly TypeMap _NVarChar = new TypeMap(OdbcType.NVarChar, DbType.String, typeof(String), ODBC32.SQL_TYPE.WVARCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.WCHAR, -1, -1, false); static private readonly TypeMap _Real = new TypeMap(OdbcType.Real, DbType.Single, typeof(Single), ODBC32.SQL_TYPE.REAL, ODBC32.SQL_C.REAL, ODBC32.SQL_C.REAL, 4, 7, false); static private readonly TypeMap _UniqueId = new TypeMap(OdbcType.UniqueIdentifier, DbType.Guid, typeof(Guid), ODBC32.SQL_TYPE.GUID, ODBC32.SQL_C.GUID, ODBC32.SQL_C.GUID, 16, 36, false); static private readonly TypeMap _SmallDT = new TypeMap(OdbcType.SmallDateTime, DbType.DateTime, typeof(DateTime), ODBC32.SQL_TYPE.TYPE_TIMESTAMP, ODBC32.SQL_C.TYPE_TIMESTAMP, ODBC32.SQL_C.TYPE_TIMESTAMP, 16, 23, false); static private readonly TypeMap _SmallInt = new TypeMap(OdbcType.SmallInt, DbType.Int16, typeof(Int16), ODBC32.SQL_TYPE.SMALLINT, ODBC32.SQL_C.SSHORT, ODBC32.SQL_C.SSHORT, 2, 5, true); static internal readonly TypeMap _Text = new TypeMap(OdbcType.Text, DbType.AnsiString, typeof(String), ODBC32.SQL_TYPE.LONGVARCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.CHAR, -1, -1, false); static private readonly TypeMap _Timestamp = new TypeMap(OdbcType.Timestamp, DbType.Binary, typeof(Byte[]), ODBC32.SQL_TYPE.BINARY, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static private readonly TypeMap _TinyInt = new TypeMap(OdbcType.TinyInt, DbType.Byte, typeof(Byte), ODBC32.SQL_TYPE.TINYINT, ODBC32.SQL_C.UTINYINT, ODBC32.SQL_C.UTINYINT, 1, 3, true); static private readonly TypeMap _VarBinary = new TypeMap(OdbcType.VarBinary, DbType.Binary, typeof(Byte[]), ODBC32.SQL_TYPE.VARBINARY, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static internal readonly TypeMap _VarChar = new TypeMap(OdbcType.VarChar, DbType.AnsiString, typeof(String), ODBC32.SQL_TYPE.VARCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.CHAR, -1, -1, false); static private readonly TypeMap _Variant = new TypeMap(OdbcType.Binary, DbType.Binary, typeof(object), ODBC32.SQL_TYPE.SS_VARIANT, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static private readonly TypeMap _UDT = new TypeMap(OdbcType.Binary, DbType.Binary, typeof(object), ODBC32.SQL_TYPE.SS_UDT, ODBC32.SQL_C.BINARY, ODBC32.SQL_C.BINARY, -1, -1, false); static private readonly TypeMap _XML = new TypeMap(OdbcType.Text, DbType.AnsiString, typeof(String), ODBC32.SQL_TYPE.LONGVARCHAR, ODBC32.SQL_C.WCHAR, ODBC32.SQL_C.CHAR, -1, -1, false); internal readonly OdbcType _odbcType; internal readonly DbType _dbType; internal readonly Type _type; internal readonly ODBC32.SQL_TYPE _sql_type; internal readonly ODBC32.SQL_C _sql_c; internal readonly ODBC32.SQL_C _param_sql_c; internal readonly int _bufferSize; // fixed length byte size to reserve for buffer internal readonly int _columnSize; // column size passed to SQLBindParameter internal readonly bool _signType; // this type may be has signature information private TypeMap(OdbcType odbcType, DbType dbType, Type type, ODBC32.SQL_TYPE sql_type, ODBC32.SQL_C sql_c, ODBC32.SQL_C param_sql_c, int bsize, int csize, bool signType) { _odbcType = odbcType; _dbType = dbType; _type = type; _sql_type = sql_type; _sql_c = sql_c; _param_sql_c = param_sql_c; // alternative sql_c type for parameters _bufferSize = bsize; _columnSize = csize; _signType = signType; } 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 ODBC.UnknownOdbcType(odbcType); } } static internal TypeMap FromDbType(DbType dbType) { switch(dbType) { case DbType.AnsiString: return _VarChar; case DbType.AnsiStringFixedLength: return _Char; case DbType.Binary: return _VarBinary; case DbType.Byte: return _TinyInt; case DbType.Boolean: return _Bit; case DbType.Currency: return _Decimal; // case DbType.Currency: return _Currency; case DbType.Date: return _Date; case DbType.Time: return _Time; case DbType.DateTime: return _DateTime; case DbType.Decimal: return _Decimal; case DbType.Double: return _Double; case DbType.Guid: return _UniqueId; case DbType.Int16: return _SmallInt; case DbType.Int32: return _Int; case DbType.Int64: return _BigInt; case DbType.Single: return _Real; case DbType.String: return _NVarChar; case DbType.StringFixedLength: return _NChar; case DbType.Object: case DbType.SByte: case DbType.UInt16: case DbType.UInt32: case DbType.UInt64: case DbType.VarNumeric: default: throw ADP.DbTypeNotSupported(dbType, typeof(OdbcType)); } } static internal TypeMap FromSystemType(Type dataType) { switch(Type.GetTypeCode(dataType)) { case TypeCode.Empty: throw ADP.InvalidDataType(TypeCode.Empty); case TypeCode.Object: if (dataType == typeof(System.Byte[])) { return _VarBinary; } else if (dataType == typeof(System.Guid)) { return _UniqueId; } else if (dataType == typeof(System.TimeSpan)) { return _Time; } else if (dataType == typeof(System.Char[])) { return _NVarChar; } throw ADP.UnknownDataType(dataType); case TypeCode.DBNull: throw ADP.InvalidDataType(TypeCode.DBNull); case TypeCode.Boolean: return _Bit; // devnote: Char is actually not supported. Our _Char type is actually a fixed length string, not a single character // case TypeCode.Char: return _Char; case TypeCode.SByte: return _SmallInt; case TypeCode.Byte: return _TinyInt; case TypeCode.Int16: return _SmallInt; case TypeCode.UInt16: return _Int; case TypeCode.Int32: return _Int; case TypeCode.UInt32: return _BigInt; case TypeCode.Int64: return _BigInt; case TypeCode.UInt64: return _Numeric; case TypeCode.Single: return _Real; case TypeCode.Double: return _Double; case TypeCode.Decimal: return _Numeric; case TypeCode.DateTime: return _DateTime; case TypeCode.Char: case TypeCode.String: return _NVarChar; default: throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType)); } } 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.TIMESTAMP: case ODBC32.SQL_TYPE.TYPE_TIMESTAMP: return _DateTime; case ODBC32.SQL_TYPE.GUID: return _UniqueId; case ODBC32.SQL_TYPE.SS_VARIANT: return _Variant; case ODBC32.SQL_TYPE.SS_UDT: return _UDT; case ODBC32.SQL_TYPE.SS_XML: return _XML; case ODBC32.SQL_TYPE.SS_UTCDATETIME: case ODBC32.SQL_TYPE.SS_TIME_EX: throw ODBC.UnknownSQLType(sqltype); default: throw ODBC.UnknownSQLType(sqltype); } } // Upgrade integer datatypes to missinterpretaion of the highest bit // (e.g. 0xff could be 255 if unsigned but is -1 if signed) // static internal TypeMap UpgradeSignedType(TypeMap typeMap, bool unsigned) { // upgrade unsigned types to be able to hold data that has the highest bit set // if (unsigned == true) { switch (typeMap._dbType) { case DbType.Int64: return _Decimal; // upgrade to decimal case DbType.Int32: return _BigInt; // upgrade to 64 bit case DbType.Int16: return _Int; // upgrade to 32 bit default: return typeMap; } // end switch } else { switch (typeMap._dbType) { case DbType.Byte: return _SmallInt; // upgrade to 16 bit default: return typeMap; } // end switch } } // end UpgradeSignedType } }