You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,150 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DbDataRecord.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.ComponentModel; //Component
|
||||
using System.Data;
|
||||
using System.Runtime.InteropServices; //Marshal
|
||||
using System.Reflection; //Missing
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
sealed internal class DbSchemaInfo {
|
||||
|
||||
internal DbSchemaInfo() {
|
||||
}
|
||||
|
||||
internal string _name;
|
||||
internal string _typename;
|
||||
internal Type _type;
|
||||
internal ODBC32.SQL_TYPE? _dbtype;
|
||||
internal object _scale;
|
||||
internal object _precision;
|
||||
|
||||
// extension to allow BindCol
|
||||
//
|
||||
internal int _columnlength; //
|
||||
internal int _valueOffset; // offset to the data in the row buffer
|
||||
internal int _lengthOffset; // offset to the length in the row buffer
|
||||
internal ODBC32.SQL_C _sqlctype; // need this to bind the value
|
||||
internal ODBC32.SQL_TYPE _sql_type; // need that to properly marshal the value
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Cache
|
||||
//
|
||||
// This is a on-demand cache, only caching what the user requests.
|
||||
// The reational is that for ForwardOnly access (the default and LCD of drivers)
|
||||
// we cannot obtain the data more than once, and even GetData(0) (to determine is-null)
|
||||
// still obtains data for fixed lenght types.
|
||||
|
||||
// So simple code like:
|
||||
// if(!rReader.IsDBNull(i))
|
||||
// rReader.GetInt32(i)
|
||||
//
|
||||
// Would fail, unless we cache on the IsDBNull call, and return the cached
|
||||
// item for GetInt32. This actually improves perf anyway, (even if the driver could
|
||||
// support it), since we are not making a seperate interop call...
|
||||
|
||||
// We do not cache all columns, so reading out of order is still not
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
sealed internal class DbCache {
|
||||
//Data
|
||||
|
||||
private bool[] _isBadValue;
|
||||
private DbSchemaInfo[] _schema;
|
||||
private object[] _values;
|
||||
private OdbcDataReader _record;
|
||||
internal int _count;
|
||||
internal bool _randomaccess = true;
|
||||
|
||||
//Constructor
|
||||
internal DbCache(OdbcDataReader record, int count) {
|
||||
_count = count;
|
||||
_record = record;
|
||||
_randomaccess = (!record.IsBehavior(CommandBehavior.SequentialAccess));
|
||||
_values = new object[count];
|
||||
_isBadValue = new bool[count];
|
||||
}
|
||||
|
||||
//Accessor
|
||||
internal object this[int i] {
|
||||
get {
|
||||
if(_isBadValue[i]) {
|
||||
OverflowException innerException = (OverflowException)Values[i];
|
||||
throw new OverflowException(innerException.Message, innerException);
|
||||
}
|
||||
return Values[i];
|
||||
}
|
||||
set {
|
||||
Values[i] = value;
|
||||
_isBadValue[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal int Count {
|
||||
get {
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
internal void InvalidateValue(int i) {
|
||||
_isBadValue[i] = true;
|
||||
}
|
||||
|
||||
internal object[] Values {
|
||||
get {
|
||||
return _values;
|
||||
}
|
||||
}
|
||||
|
||||
internal object AccessIndex(int i) {
|
||||
//Note: We could put this directly in this[i], instead of having an explicit overload.
|
||||
//However that means that EVERY access into the cache takes the hit of checking, so
|
||||
//something as simple as the following code would take two hits. It's nice not to
|
||||
//have to take the hit when you know what your doing.
|
||||
//
|
||||
// if(cache[i] == null)
|
||||
// ....
|
||||
// return cache[i];
|
||||
|
||||
object[] values = this.Values;
|
||||
if(_randomaccess) {
|
||||
//Random
|
||||
//Means that the user can ask for the values int any order (ie: out of order).
|
||||
// In order to acheive this on a forward only stream, we need to actually
|
||||
// retreive all the value in between so they can go back to values they've skipped
|
||||
for(int c = 0; c < i; c++) {
|
||||
if(values[c] == null) {
|
||||
values[c] = _record.GetValue(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return values[i];
|
||||
}
|
||||
|
||||
internal DbSchemaInfo GetSchema(int i) {
|
||||
if(_schema == null) {
|
||||
_schema = new DbSchemaInfo[Count];
|
||||
}
|
||||
if(_schema[i] == null) {
|
||||
_schema[i] = new DbSchemaInfo();
|
||||
}
|
||||
return _schema[i];
|
||||
}
|
||||
|
||||
internal void FlushValues() {
|
||||
//Set all objects to null (to explcitly release them)
|
||||
//Note: SchemaInfo remains the same for all rows - no need to reget those...
|
||||
int count = _values.Length;
|
||||
for(int i = 0; i < count; ++i) {
|
||||
_values[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1002
mcs/class/referencesource/System.Data/System/Data/Odbc/Odbc32.cs
Normal file
1002
mcs/class/referencesource/System.Data/System/Data/Odbc/Odbc32.cs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,327 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcCommandBuilder.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
public sealed class OdbcCommandBuilder : DbCommandBuilder {
|
||||
|
||||
public OdbcCommandBuilder() : base() {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public OdbcCommandBuilder(OdbcDataAdapter adapter) : this() {
|
||||
DataAdapter = adapter;
|
||||
}
|
||||
|
||||
[
|
||||
DefaultValue(null),
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.OdbcCommandBuilder_DataAdapter), // MDAC 60524
|
||||
]
|
||||
new public OdbcDataAdapter DataAdapter {
|
||||
get {
|
||||
return (base.DataAdapter as OdbcDataAdapter);
|
||||
}
|
||||
set {
|
||||
base.DataAdapter = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void OdbcRowUpdatingHandler(object sender, OdbcRowUpdatingEventArgs ruevent) {
|
||||
RowUpdatingHandler(ruevent);
|
||||
}
|
||||
|
||||
new public OdbcCommand GetInsertCommand() {
|
||||
return (OdbcCommand) base.GetInsertCommand();
|
||||
}
|
||||
new public OdbcCommand GetInsertCommand(bool useColumnsForParameterNames) {
|
||||
return (OdbcCommand) base.GetInsertCommand(useColumnsForParameterNames);
|
||||
}
|
||||
|
||||
new public OdbcCommand GetUpdateCommand() {
|
||||
return (OdbcCommand) base.GetUpdateCommand();
|
||||
}
|
||||
new public OdbcCommand GetUpdateCommand(bool useColumnsForParameterNames) {
|
||||
return (OdbcCommand) base.GetUpdateCommand(useColumnsForParameterNames);
|
||||
}
|
||||
|
||||
new public OdbcCommand GetDeleteCommand() {
|
||||
return (OdbcCommand) base.GetDeleteCommand();
|
||||
}
|
||||
new public OdbcCommand GetDeleteCommand(bool useColumnsForParameterNames) {
|
||||
return (OdbcCommand) base.GetDeleteCommand(useColumnsForParameterNames);
|
||||
}
|
||||
|
||||
override protected string GetParameterName(int parameterOrdinal) {
|
||||
return "p" + parameterOrdinal.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
override protected string GetParameterName(string parameterName) {
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
override protected string GetParameterPlaceholder(int parameterOrdinal) {
|
||||
return "?";
|
||||
}
|
||||
|
||||
override protected void ApplyParameterInfo(DbParameter parameter, DataRow datarow, StatementType statementType, bool whereClause) {
|
||||
OdbcParameter p = (OdbcParameter) parameter;
|
||||
object valueType = datarow[SchemaTableColumn.ProviderType];
|
||||
p.OdbcType = (OdbcType) valueType;
|
||||
|
||||
object bvalue = datarow[SchemaTableColumn.NumericPrecision];
|
||||
if (DBNull.Value != bvalue) {
|
||||
byte bval = (byte)(short)bvalue;
|
||||
p.PrecisionInternal = ((0xff != bval) ? bval : (byte)0);
|
||||
}
|
||||
|
||||
bvalue = datarow[SchemaTableColumn.NumericScale];
|
||||
if (DBNull.Value != bvalue) {
|
||||
byte bval = (byte)(short)bvalue;
|
||||
p.ScaleInternal = ((0xff != bval) ? bval : (byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
static public void DeriveParameters(OdbcCommand command) {
|
||||
// MDAC 65927
|
||||
OdbcConnection.ExecutePermission.Demand();
|
||||
|
||||
if (null == command) {
|
||||
throw ADP.ArgumentNull("command");
|
||||
}
|
||||
switch (command.CommandType) {
|
||||
case System.Data.CommandType.Text:
|
||||
throw ADP.DeriveParametersNotSupported(command);
|
||||
case System.Data.CommandType.StoredProcedure:
|
||||
break;
|
||||
case System.Data.CommandType.TableDirect:
|
||||
// CommandType.TableDirect - do nothing, parameters are not supported
|
||||
throw ADP.DeriveParametersNotSupported(command);
|
||||
default:
|
||||
throw ADP.InvalidCommandType(command.CommandType);
|
||||
}
|
||||
if (ADP.IsEmpty(command.CommandText)) {
|
||||
throw ADP.CommandTextRequired(ADP.DeriveParameters);
|
||||
}
|
||||
|
||||
OdbcConnection connection = command.Connection;
|
||||
|
||||
if (null == connection) {
|
||||
throw ADP.ConnectionRequired(ADP.DeriveParameters);
|
||||
}
|
||||
|
||||
ConnectionState state = connection.State;
|
||||
|
||||
if (ConnectionState.Open != state) {
|
||||
throw ADP.OpenConnectionRequired(ADP.DeriveParameters, state);
|
||||
}
|
||||
|
||||
OdbcParameter[] list = DeriveParametersFromStoredProcedure(connection, command);
|
||||
|
||||
OdbcParameterCollection parameters = command.Parameters;
|
||||
parameters.Clear();
|
||||
|
||||
int count = list.Length;
|
||||
if (0 < count) {
|
||||
for(int i = 0; i < list.Length; ++i) {
|
||||
parameters.Add(list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DeriveParametersFromStoredProcedure (
|
||||
// OdbcConnection connection,
|
||||
// OdbcCommand command);
|
||||
//
|
||||
// Uses SQLProcedureColumns to create an array of OdbcParameters
|
||||
//
|
||||
|
||||
static private OdbcParameter[] DeriveParametersFromStoredProcedure(OdbcConnection connection, OdbcCommand command) {
|
||||
List<OdbcParameter> rParams = new List<OdbcParameter>();
|
||||
|
||||
// following call ensures that the command has a statement handle allocated
|
||||
CMDWrapper cmdWrapper = command.GetStatementHandle();
|
||||
OdbcStatementHandle hstmt = cmdWrapper.StatementHandle;
|
||||
int cColsAffected;
|
||||
|
||||
// maps an enforced 4-part qualified string as follows
|
||||
// parts[0] = null - ignored but removal would be a run-time breaking change from V1.0
|
||||
// parts[1] = CatalogName (optional, may be null)
|
||||
// parts[2] = SchemaName (optional, may be null)
|
||||
// parts[3] = ProcedureName
|
||||
//
|
||||
string quote = connection.QuoteChar(ADP.DeriveParameters);
|
||||
string[] parts = MultipartIdentifier.ParseMultipartIdentifier(command.CommandText, quote, quote, '.', 4, true, Res.ODBC_ODBCCommandText, false);
|
||||
if (null == parts[3]) { // match everett behavior, if the commandtext is nothing but whitespace set the command text to the whitespace
|
||||
parts[3] = command.CommandText;
|
||||
}
|
||||
// note: native odbc appears to ignore all but the procedure name
|
||||
ODBC32.RetCode retcode = hstmt.ProcedureColumns(parts[1], parts[2], parts[3], null);
|
||||
|
||||
// Note: the driver does not return an error if the given stored procedure does not exist
|
||||
// therefore we cannot handle that case and just return not parameters.
|
||||
|
||||
if (ODBC32.RetCode.SUCCESS != retcode) {
|
||||
connection.HandleError(hstmt, retcode);
|
||||
}
|
||||
|
||||
using (OdbcDataReader reader = new OdbcDataReader(command, cmdWrapper, CommandBehavior.Default)) {
|
||||
reader.FirstResult();
|
||||
cColsAffected = reader.FieldCount;
|
||||
|
||||
// go through the returned rows and filter out relevant parameter data
|
||||
//
|
||||
while (reader.Read()) {
|
||||
// devnote: column types are specified in the ODBC Programmer's Reference
|
||||
// COLUMN_TYPE Smallint 16bit
|
||||
// COLUMN_SIZE Integer 32bit
|
||||
// DECIMAL_DIGITS Smallint 16bit
|
||||
// NUM_PREC_RADIX Smallint 16bit
|
||||
|
||||
OdbcParameter parameter = new OdbcParameter();
|
||||
|
||||
parameter.ParameterName = reader.GetString(ODBC32.COLUMN_NAME-1);
|
||||
switch ((ODBC32.SQL_PARAM)reader.GetInt16(ODBC32.COLUMN_TYPE-1)){
|
||||
case ODBC32.SQL_PARAM.INPUT:
|
||||
parameter.Direction = ParameterDirection.Input;
|
||||
break;
|
||||
case ODBC32.SQL_PARAM.OUTPUT:
|
||||
parameter.Direction = ParameterDirection.Output;
|
||||
break;
|
||||
|
||||
case ODBC32.SQL_PARAM.INPUT_OUTPUT:
|
||||
parameter.Direction = ParameterDirection.InputOutput;
|
||||
break;
|
||||
case ODBC32.SQL_PARAM.RETURN_VALUE:
|
||||
parameter.Direction = ParameterDirection.ReturnValue;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, "Unexpected Parametertype while DeriveParamters");
|
||||
break;
|
||||
}
|
||||
parameter.OdbcType = TypeMap.FromSqlType((ODBC32.SQL_TYPE)reader.GetInt16(ODBC32.DATA_TYPE-1))._odbcType;
|
||||
parameter.Size = (int)reader.GetInt32(ODBC32.COLUMN_SIZE-1);
|
||||
switch(parameter.OdbcType){
|
||||
case OdbcType.Decimal:
|
||||
case OdbcType.Numeric:
|
||||
parameter.ScaleInternal = (Byte)reader.GetInt16(ODBC32.DECIMAL_DIGITS-1);
|
||||
parameter.PrecisionInternal = (Byte)reader.GetInt16(ODBC32.NUM_PREC_RADIX-1);
|
||||
break;
|
||||
}
|
||||
rParams.Add (parameter);
|
||||
}
|
||||
}
|
||||
retcode = hstmt.CloseCursor();
|
||||
return rParams.ToArray();;
|
||||
}
|
||||
|
||||
public override string QuoteIdentifier(string unquotedIdentifier){
|
||||
return QuoteIdentifier(unquotedIdentifier, null /* use DataAdapter.SelectCommand.Connection if available */);
|
||||
}
|
||||
public string QuoteIdentifier( string unquotedIdentifier, OdbcConnection connection){
|
||||
|
||||
ADP.CheckArgumentNull(unquotedIdentifier, "unquotedIdentifier");
|
||||
|
||||
// if the user has specificed a prefix use the user specified prefix and suffix
|
||||
// otherwise get them from the provider
|
||||
string quotePrefix = QuotePrefix;
|
||||
string quoteSuffix = QuoteSuffix;
|
||||
if (ADP.IsEmpty(quotePrefix) == true) {
|
||||
if (connection == null) {
|
||||
// VSTFDEVDIV 479567: use the adapter's connection if QuoteIdentifier was called from
|
||||
// DbCommandBuilder instance (which does not have an overload that gets connection object)
|
||||
connection = base.GetConnection() as OdbcConnection;
|
||||
if (connection == null) {
|
||||
throw ADP.QuotePrefixNotSet(ADP.QuoteIdentifier);
|
||||
}
|
||||
}
|
||||
quotePrefix = connection.QuoteChar(ADP.QuoteIdentifier);
|
||||
quoteSuffix = quotePrefix;
|
||||
}
|
||||
|
||||
// by the ODBC spec "If the data source does not support quoted identifiers, a blank is returned."
|
||||
// So if a blank is returned the string is returned unchanged. Otherwise the returned string is used
|
||||
// to quote the string
|
||||
if ((ADP.IsEmpty(quotePrefix) == false) && (quotePrefix != " ")) {
|
||||
return ADP.BuildQuotedString(quotePrefix,quoteSuffix,unquotedIdentifier);
|
||||
}
|
||||
else {
|
||||
return unquotedIdentifier;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override protected void SetRowUpdatingHandler(DbDataAdapter adapter) {
|
||||
Debug.Assert(adapter is OdbcDataAdapter, "!OdbcDataAdapter");
|
||||
if (adapter == base.DataAdapter) { // removal case
|
||||
((OdbcDataAdapter)adapter).RowUpdating -= OdbcRowUpdatingHandler;
|
||||
}
|
||||
else { // adding case
|
||||
((OdbcDataAdapter)adapter).RowUpdating += OdbcRowUpdatingHandler;
|
||||
}
|
||||
}
|
||||
|
||||
public override string UnquoteIdentifier( string quotedIdentifier){
|
||||
return UnquoteIdentifier(quotedIdentifier, null /* use DataAdapter.SelectCommand.Connection if available */);
|
||||
}
|
||||
|
||||
public string UnquoteIdentifier(string quotedIdentifier, OdbcConnection connection){
|
||||
|
||||
ADP.CheckArgumentNull(quotedIdentifier, "quotedIdentifier");
|
||||
|
||||
|
||||
// if the user has specificed a prefix use the user specified prefix and suffix
|
||||
// otherwise get them from the provider
|
||||
string quotePrefix = QuotePrefix;
|
||||
string quoteSuffix = QuoteSuffix;
|
||||
if (ADP.IsEmpty(quotePrefix) == true) {
|
||||
if (connection == null) {
|
||||
// VSTFDEVDIV 479567: use the adapter's connection if UnquoteIdentifier was called from
|
||||
// DbCommandBuilder instance (which does not have an overload that gets connection object)
|
||||
connection = base.GetConnection() as OdbcConnection;
|
||||
if (connection == null) {
|
||||
throw ADP.QuotePrefixNotSet(ADP.UnquoteIdentifier);
|
||||
}
|
||||
}
|
||||
quotePrefix = connection.QuoteChar(ADP.UnquoteIdentifier);
|
||||
quoteSuffix = quotePrefix;
|
||||
}
|
||||
|
||||
String unquotedIdentifier;
|
||||
// by the ODBC spec "If the data source does not support quoted identifiers, a blank is returned."
|
||||
// So if a blank is returned the string is returned unchanged. Otherwise the returned string is used
|
||||
// to unquote the string
|
||||
if ((ADP.IsEmpty(quotePrefix) == false) || (quotePrefix != " ")) {
|
||||
// ignoring the return value because it is acceptable for the quotedString to not be quoted in this
|
||||
// context.
|
||||
ADP.RemoveStringQuotes(quotePrefix, quoteSuffix, quotedIdentifier, out unquotedIdentifier);
|
||||
}
|
||||
else {
|
||||
unquotedIdentifier = quotedIdentifier;
|
||||
}
|
||||
return unquotedIdentifier;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionFactory.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Odbc
|
||||
{
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
sealed internal class OdbcConnectionFactory : DbConnectionFactory {
|
||||
private OdbcConnectionFactory() : base() {}
|
||||
// At this time, the ODBC Provider doesn't have any connection pool counters
|
||||
// because we'd only confuse people with "non-pooled" connections that are
|
||||
// actually being pooled by the native pooler.
|
||||
|
||||
private const string _MetaData = ":MetaDataXml";
|
||||
private const string _defaultMetaDataXml = "defaultMetaDataXml";
|
||||
|
||||
public static readonly OdbcConnectionFactory SingletonInstance = new OdbcConnectionFactory();
|
||||
|
||||
override public DbProviderFactory ProviderFactory {
|
||||
get {
|
||||
return OdbcFactory.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningObject) {
|
||||
DbConnectionInternal result = new OdbcConnectionOpen(owningObject as OdbcConnection, options as OdbcConnectionString);
|
||||
return result;
|
||||
}
|
||||
|
||||
override protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous) {
|
||||
Debug.Assert(!ADP.IsEmpty(connectionString), "empty connectionString");
|
||||
OdbcConnectionString result = new OdbcConnectionString(connectionString, (null != previous));
|
||||
return result;
|
||||
}
|
||||
|
||||
override protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions( DbConnectionOptions connectionOptions ) {
|
||||
// At this time, the ODBC provider only supports native pooling so we
|
||||
// simply return NULL to indicate that.
|
||||
return null;
|
||||
}
|
||||
|
||||
override internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo (DbConnectionOptions connectionOptions) {
|
||||
return new OdbcConnectionPoolGroupProviderInfo();
|
||||
}
|
||||
|
||||
// SxS (VSDD 545786): metadata files are opened from <.NetRuntimeFolder>\CONFIG\<metadatafilename.xml>
|
||||
// this operation is safe in SxS because the file is opened in read-only mode and each NDP runtime accesses its own copy of the metadata
|
||||
// under the runtime folder.
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
|
||||
override protected DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory){
|
||||
|
||||
Debug.Assert (internalConnection != null,"internalConnection may not be null.");
|
||||
cacheMetaDataFactory = false;
|
||||
|
||||
OdbcConnection odbcOuterConnection = ((OdbcConnectionOpen)internalConnection).OuterConnection;
|
||||
Debug.Assert(odbcOuterConnection != null,"outer connection may not be null.");
|
||||
|
||||
NameValueCollection settings = (NameValueCollection)PrivilegedConfigurationManager.GetSection("system.data.odbc");
|
||||
Stream XMLStream =null;
|
||||
|
||||
// get the DBMS Name
|
||||
object driverName = null;
|
||||
string stringValue = odbcOuterConnection.GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_NAME);
|
||||
if (stringValue != null) {
|
||||
driverName = stringValue;
|
||||
}
|
||||
|
||||
if (settings != null){
|
||||
|
||||
string [] values = null;
|
||||
string metaDataXML = null;
|
||||
// first try to get the provider specific xml
|
||||
|
||||
// if driver name is not supported we can't build the settings key needed to
|
||||
// get the provider specific XML path
|
||||
if (driverName != null){
|
||||
metaDataXML = ((string)driverName) + _MetaData;
|
||||
values = settings.GetValues(metaDataXML);
|
||||
}
|
||||
|
||||
// if we did not find provider specific xml see if there is new default xml
|
||||
if (values == null) {
|
||||
metaDataXML = _defaultMetaDataXml;
|
||||
values = settings.GetValues(metaDataXML);
|
||||
}
|
||||
|
||||
// If there is an XML file get it
|
||||
if (values != null) {
|
||||
XMLStream = ADP.GetXmlStreamFromValues(values,metaDataXML);
|
||||
}
|
||||
}
|
||||
|
||||
// use the embedded xml if the user did not over ride it
|
||||
if (XMLStream == null){
|
||||
XMLStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("System.Data.Odbc.OdbcMetaData.xml");
|
||||
cacheMetaDataFactory = true;
|
||||
}
|
||||
|
||||
Debug.Assert (XMLStream != null,"XMLstream may not be null.");
|
||||
|
||||
String versionString = odbcOuterConnection.GetInfoStringUnhandled(ODBC32.SQL_INFO.DBMS_VER);
|
||||
|
||||
return new OdbcMetaDataFactory (XMLStream,
|
||||
versionString,
|
||||
versionString,
|
||||
odbcOuterConnection);
|
||||
}
|
||||
|
||||
override internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection) {
|
||||
OdbcConnection c = (connection as OdbcConnection);
|
||||
if (null != c) {
|
||||
return c.PoolGroup;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
override internal DbConnectionInternal GetInnerConnection(DbConnection connection) {
|
||||
OdbcConnection c = (connection as OdbcConnection);
|
||||
if (null != c) {
|
||||
return c.InnerConnection;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
override protected int GetObjectId(DbConnection connection) {
|
||||
OdbcConnection c = (connection as OdbcConnection);
|
||||
if (null != c) {
|
||||
return c.ObjectID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
override internal void PermissionDemand(DbConnection outerConnection) {
|
||||
OdbcConnection c = (outerConnection as OdbcConnection);
|
||||
if (null != c) {
|
||||
c.PermissionDemand();
|
||||
}
|
||||
}
|
||||
|
||||
override internal void SetConnectionPoolGroup(DbConnection outerConnection, DbConnectionPoolGroup poolGroup) {
|
||||
OdbcConnection c = (outerConnection as OdbcConnection);
|
||||
if (null != c) {
|
||||
c.PoolGroup = poolGroup;
|
||||
}
|
||||
}
|
||||
|
||||
override internal void SetInnerConnectionEvent(DbConnection owningObject, DbConnectionInternal to) {
|
||||
OdbcConnection c = (owningObject as OdbcConnection);
|
||||
if (null != c) {
|
||||
c.SetInnerConnectionEvent(to);
|
||||
}
|
||||
}
|
||||
|
||||
override internal bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from) {
|
||||
OdbcConnection c = (owningObject as OdbcConnection);
|
||||
if (null != c) {
|
||||
return c.SetInnerConnectionFrom(to, from);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
override internal void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to) {
|
||||
OdbcConnection c = (owningObject as OdbcConnection);
|
||||
if (null != c) {
|
||||
c.SetInnerConnectionTo(to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,265 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionHandle.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
sealed internal class OdbcConnectionHandle : OdbcHandle {
|
||||
private HandleState _handleState;
|
||||
|
||||
private enum HandleState {
|
||||
Allocated = 0,
|
||||
Connected = 1,
|
||||
Transacted = 2,
|
||||
TransactionInProgress = 3,
|
||||
}
|
||||
|
||||
internal OdbcConnectionHandle(OdbcConnection connection, OdbcConnectionString constr, OdbcEnvironmentHandle environmentHandle) : base(ODBC32.SQL_HANDLE.DBC, environmentHandle) {
|
||||
if(null == connection) {
|
||||
throw ADP.ArgumentNull("connection");
|
||||
}
|
||||
if(null == constr) {
|
||||
throw ADP.ArgumentNull("constr");
|
||||
}
|
||||
|
||||
ODBC32.RetCode retcode;
|
||||
|
||||
//Set connection timeout (only before open).
|
||||
//Note: We use login timeout since its odbc 1.0 option, instead of using
|
||||
//connectiontimeout (which affects other things besides just login) and its
|
||||
//a odbc 3.0 feature. The ConnectionTimeout on the managed providers represents
|
||||
//the login timeout, nothing more.
|
||||
int connectionTimeout = connection.ConnectionTimeout;
|
||||
retcode = SetConnectionAttribute2(ODBC32.SQL_ATTR.LOGIN_TIMEOUT, (IntPtr)connectionTimeout, (Int32)ODBC32.SQL_IS.UINTEGER);
|
||||
|
||||
string connectionString = constr.UsersConnectionString(false);
|
||||
|
||||
// Connect to the driver. (Using the connection string supplied)
|
||||
//Note: The driver doesn't filter out the password in the returned connection string
|
||||
//so their is no need for us to obtain the returned connection string
|
||||
// Prepare to handle a ThreadAbort Exception between SQLDriverConnectW and update of the state variables
|
||||
retcode = Connect(connectionString);
|
||||
connection.HandleError(this, retcode);
|
||||
}
|
||||
|
||||
private ODBC32.RetCode AutoCommitOff() {
|
||||
ODBC32.RetCode retcode;
|
||||
|
||||
Debug.Assert(HandleState.Connected <= _handleState, "AutoCommitOff while in wrong state?");
|
||||
|
||||
// Avoid runtime injected errors in the following block.
|
||||
// must call SQLSetConnectAttrW and set _handleState
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {} finally {
|
||||
retcode = UnsafeNativeMethods.SQLSetConnectAttrW(this, ODBC32.SQL_ATTR.AUTOCOMMIT, ODBC32.SQL_AUTOCOMMIT_OFF, (Int32)ODBC32.SQL_IS.UINTEGER);
|
||||
switch(retcode) {
|
||||
case ODBC32.RetCode.SUCCESS:
|
||||
case ODBC32.RetCode.SUCCESS_WITH_INFO:
|
||||
_handleState = HandleState.Transacted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ODBC.TraceODBC(3, "SQLSetConnectAttrW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode BeginTransaction(ref IsolationLevel isolevel) {
|
||||
ODBC32.RetCode retcode = ODBC32.RetCode.SUCCESS;
|
||||
ODBC32.SQL_ATTR isolationAttribute;
|
||||
if(IsolationLevel.Unspecified != isolevel) {
|
||||
ODBC32.SQL_TRANSACTION sql_iso;
|
||||
switch(isolevel) {
|
||||
case IsolationLevel.ReadUncommitted:
|
||||
sql_iso = ODBC32.SQL_TRANSACTION.READ_UNCOMMITTED;
|
||||
isolationAttribute = ODBC32.SQL_ATTR.TXN_ISOLATION;
|
||||
break;
|
||||
case IsolationLevel.ReadCommitted:
|
||||
sql_iso = ODBC32.SQL_TRANSACTION.READ_COMMITTED;
|
||||
isolationAttribute = ODBC32.SQL_ATTR.TXN_ISOLATION;
|
||||
break;
|
||||
case IsolationLevel.RepeatableRead:
|
||||
sql_iso = ODBC32.SQL_TRANSACTION.REPEATABLE_READ;
|
||||
isolationAttribute = ODBC32.SQL_ATTR.TXN_ISOLATION;
|
||||
break;
|
||||
case IsolationLevel.Serializable:
|
||||
sql_iso = ODBC32.SQL_TRANSACTION.SERIALIZABLE;
|
||||
isolationAttribute = ODBC32.SQL_ATTR.TXN_ISOLATION;
|
||||
break;
|
||||
case IsolationLevel.Snapshot:
|
||||
sql_iso = ODBC32.SQL_TRANSACTION.SNAPSHOT;
|
||||
// VSDD 414121: Snapshot isolation level must be set through SQL_COPT_SS_TXN_ISOLATION (http://msdn.microsoft.com/en-us/library/ms131709.aspx)
|
||||
isolationAttribute = ODBC32.SQL_ATTR.SQL_COPT_SS_TXN_ISOLATION;
|
||||
break;
|
||||
case IsolationLevel.Chaos:
|
||||
throw ODBC.NotSupportedIsolationLevel(isolevel);
|
||||
default:
|
||||
throw ADP.InvalidIsolationLevel(isolevel);
|
||||
}
|
||||
|
||||
//Set the isolation level (unless its unspecified)
|
||||
retcode = SetConnectionAttribute2(isolationAttribute, (IntPtr)sql_iso, (Int32)ODBC32.SQL_IS.INTEGER);
|
||||
|
||||
//Note: The Driver can return success_with_info to indicate it "rolled" the
|
||||
//isolevel to the next higher value. If this is the case, we need to requery
|
||||
//the value if th euser asks for it...
|
||||
//We also still propagate the info, since it could be other info as well...
|
||||
|
||||
if(ODBC32.RetCode.SUCCESS_WITH_INFO == retcode) {
|
||||
isolevel = IsolationLevel.Unspecified;
|
||||
}
|
||||
}
|
||||
|
||||
switch(retcode) {
|
||||
case ODBC32.RetCode.SUCCESS:
|
||||
case ODBC32.RetCode.SUCCESS_WITH_INFO:
|
||||
//Turn off auto-commit (which basically starts the transaction)
|
||||
retcode = AutoCommitOff();
|
||||
_handleState = HandleState.TransactionInProgress;
|
||||
break;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode CompleteTransaction(short transactionOperation) {
|
||||
bool mustRelease = false;
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
DangerousAddRef(ref mustRelease);
|
||||
ODBC32.RetCode retcode = CompleteTransaction(transactionOperation, base.handle);
|
||||
return retcode;
|
||||
}
|
||||
finally {
|
||||
if (mustRelease) {
|
||||
DangerousRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
private ODBC32.RetCode CompleteTransaction(short transactionOperation, IntPtr handle) {
|
||||
// must only call this code from ReleaseHandle or DangerousAddRef region
|
||||
|
||||
ODBC32.RetCode retcode = ODBC32.RetCode.SUCCESS;
|
||||
|
||||
// using ConstrainedRegions to make the native ODBC call and change the _handleState
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { } finally {
|
||||
if (HandleState.TransactionInProgress == _handleState) {
|
||||
retcode = UnsafeNativeMethods.SQLEndTran(HandleType, handle, transactionOperation);
|
||||
if((ODBC32.RetCode.SUCCESS == retcode) || (ODBC32.RetCode.SUCCESS_WITH_INFO == retcode)) {
|
||||
_handleState = HandleState.Transacted;
|
||||
}
|
||||
Bid.TraceSqlReturn("<odbc.SQLEndTran|API|ODBC|RET> %08X{SQLRETURN}\n", retcode);
|
||||
}
|
||||
|
||||
if (HandleState.Transacted == _handleState) { // AutoCommitOn
|
||||
retcode = UnsafeNativeMethods.SQLSetConnectAttrW(handle, ODBC32.SQL_ATTR.AUTOCOMMIT, ODBC32.SQL_AUTOCOMMIT_ON, (Int32)ODBC32.SQL_IS.UINTEGER);
|
||||
_handleState = HandleState.Connected;
|
||||
Bid.TraceSqlReturn("<odbc.SQLSetConnectAttr|API|ODBC|RET> %08X{SQLRETURN}\n", retcode);
|
||||
}
|
||||
}
|
||||
//Overactive assert which fires if handle was allocated - but failed to connect to the server
|
||||
//it can more legitmately fire if transaction failed to rollback - but there isn't much we can do in that situation
|
||||
//Debug.Assert((HandleState.Connected == _handleState) || (HandleState.TransactionInProgress == _handleState), "not expected HandleState.Connected");
|
||||
return retcode;
|
||||
}
|
||||
private ODBC32.RetCode Connect(string connectionString) {
|
||||
Debug.Assert(HandleState.Allocated == _handleState, "SQLDriverConnect while in wrong state?");
|
||||
|
||||
ODBC32.RetCode retcode;
|
||||
|
||||
// Avoid runtime injected errors in the following block.
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {} finally {
|
||||
|
||||
short cbActualSize;
|
||||
retcode = UnsafeNativeMethods.SQLDriverConnectW(this, ADP.PtrZero, connectionString, ODBC32.SQL_NTS, ADP.PtrZero, 0, out cbActualSize, (short)ODBC32.SQL_DRIVER.NOPROMPT);
|
||||
switch(retcode) {
|
||||
case ODBC32.RetCode.SUCCESS:
|
||||
case ODBC32.RetCode.SUCCESS_WITH_INFO:
|
||||
_handleState = HandleState.Connected;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ODBC.TraceODBC(3, "SQLDriverConnectW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
override protected bool ReleaseHandle() {
|
||||
// NOTE: The SafeHandle class guarantees this will be called exactly once and is non-interrutible.
|
||||
ODBC32.RetCode retcode;
|
||||
|
||||
// must call complete the transaction rollback, change handle state, and disconnect the connection
|
||||
retcode = CompleteTransaction(ODBC32.SQL_ROLLBACK, handle);
|
||||
|
||||
if ((HandleState.Connected == _handleState) || (HandleState.TransactionInProgress == _handleState)) {
|
||||
retcode = UnsafeNativeMethods.SQLDisconnect(handle);
|
||||
_handleState = HandleState.Allocated;
|
||||
Bid.TraceSqlReturn("<odbc.SQLDisconnect|API|ODBC|RET> %08X{SQLRETURN}\n", retcode);
|
||||
}
|
||||
Debug.Assert(HandleState.Allocated == _handleState, "not expected HandleState.Allocated");
|
||||
return base.ReleaseHandle();
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetConnectionAttribute(ODBC32.SQL_ATTR attribute, byte[] buffer, out int cbActual) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetConnectAttrW(this, attribute, buffer, buffer.Length, out cbActual);
|
||||
Bid.Trace("<odbc.SQLGetConnectAttr|ODBC> SQLRETURN=%d, Attribute=%d, BufferLength=%d, StringLength=%d\n", (int)retcode, (int)attribute, buffer.Length, (int)cbActual);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetFunctions(ODBC32.SQL_API fFunction, out Int16 fExists) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetFunctions(this, fFunction, out fExists);
|
||||
ODBC.TraceODBC(3, "SQLGetFunctions", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetInfo2(ODBC32.SQL_INFO info, byte[] buffer, out short cbActual) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetInfoW(this, info, buffer, checked((short)buffer.Length), out cbActual);
|
||||
Bid.Trace("<odbc.SQLGetInfo|ODBC> SQLRETURN=%d, InfoType=%d, BufferLength=%d, StringLength=%d\n", (int)retcode, (int)info, buffer.Length, (int)cbActual);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetInfo1(ODBC32.SQL_INFO info, byte[] buffer) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetInfoW(this, info, buffer, checked((short)buffer.Length), ADP.PtrZero);
|
||||
Bid.Trace("<odbc.SQLGetInfo|ODBC> SQLRETURN=%d, InfoType=%d, BufferLength=%d\n", (int)retcode, (int)info, buffer.Length);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode SetConnectionAttribute2(ODBC32.SQL_ATTR attribute, IntPtr value, Int32 length) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLSetConnectAttrW(this, attribute, value, length);
|
||||
ODBC.TraceODBC(3, "SQLSetConnectAttrW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode SetConnectionAttribute3(ODBC32.SQL_ATTR attribute, string buffer, Int32 length) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLSetConnectAttrW(this, attribute, buffer, length);
|
||||
Bid.Trace("<odbc.SQLSetConnectAttr|ODBC> SQLRETURN=%d, Attribute=%d, BufferLength=%d\n", (int)retcode, (int)attribute, buffer.Length);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode SetConnectionAttribute4(ODBC32.SQL_ATTR attribute, System.Transactions.IDtcTransaction transaction, Int32 length) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLSetConnectAttrW(this, attribute, transaction, length);
|
||||
ODBC.TraceODBC(3, "SQLSetConnectAttrW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionOpen.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.ProviderBase;
|
||||
using System.Threading;
|
||||
using SysTx = System.Transactions;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
sealed internal class OdbcConnectionOpen : DbConnectionInternal {
|
||||
|
||||
// Construct from a compiled connection string
|
||||
internal OdbcConnectionOpen(OdbcConnection outerConnection, OdbcConnectionString connectionOptions) {
|
||||
#if DEBUG
|
||||
try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath
|
||||
if (null != outerConnection) {
|
||||
outerConnection.UserConnectionOptions.DemandPermission();
|
||||
}
|
||||
else {
|
||||
connectionOptions.DemandPermission();
|
||||
}
|
||||
}
|
||||
catch(System.Security.SecurityException) {
|
||||
System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
OdbcEnvironmentHandle environmentHandle = OdbcEnvironment.GetGlobalEnvironmentHandle();
|
||||
outerConnection.ConnectionHandle = new OdbcConnectionHandle(outerConnection, connectionOptions, environmentHandle);
|
||||
}
|
||||
|
||||
internal OdbcConnection OuterConnection {
|
||||
get {
|
||||
OdbcConnection outerConnection = (OdbcConnection)Owner;
|
||||
|
||||
if (null == outerConnection)
|
||||
throw ODBC.OpenConnectionNoOwner();
|
||||
|
||||
return outerConnection;
|
||||
}
|
||||
}
|
||||
|
||||
override public string ServerVersion {
|
||||
get {
|
||||
return OuterConnection.Open_GetServerVersion();
|
||||
}
|
||||
}
|
||||
|
||||
override protected void Activate(SysTx.Transaction transaction) {
|
||||
OdbcConnection.ExecutePermission.Demand();
|
||||
}
|
||||
|
||||
override public DbTransaction BeginTransaction(IsolationLevel isolevel) {
|
||||
return BeginOdbcTransaction(isolevel);
|
||||
}
|
||||
|
||||
internal OdbcTransaction BeginOdbcTransaction(IsolationLevel isolevel) {
|
||||
return OuterConnection.Open_BeginTransaction(isolevel);
|
||||
}
|
||||
|
||||
override public void ChangeDatabase(string value) {
|
||||
OuterConnection.Open_ChangeDatabase(value);
|
||||
}
|
||||
|
||||
override protected DbReferenceCollection CreateReferenceCollection() {
|
||||
return new OdbcReferenceCollection();
|
||||
}
|
||||
|
||||
override protected void Deactivate() {
|
||||
NotifyWeakReference(OdbcReferenceCollection.Closing);
|
||||
}
|
||||
|
||||
override public void EnlistTransaction(SysTx.Transaction transaction) {
|
||||
OuterConnection.Open_EnlistTransaction(transaction);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,202 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionPoolProviderInfo.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Odbc
|
||||
{
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.ProviderBase;
|
||||
|
||||
sealed internal class OdbcConnectionPoolGroupProviderInfo : DbConnectionPoolGroupProviderInfo {
|
||||
private string _driverName;
|
||||
private string _driverVersion;
|
||||
private string _quoteChar;
|
||||
|
||||
private char _escapeChar;
|
||||
private bool _hasQuoteChar;
|
||||
private bool _hasEscapeChar;
|
||||
|
||||
private bool _isV3Driver;
|
||||
private int _supportedSQLTypes;
|
||||
private int _testedSQLTypes;
|
||||
private int _restrictedSQLBindTypes; // These, otherwise supported types, are not available for binding
|
||||
|
||||
// flags for unsupported Attributes
|
||||
private bool _noCurrentCatalog;
|
||||
private bool _noConnectionDead;
|
||||
|
||||
private bool _noQueryTimeout;
|
||||
private bool _noSqlSoptSSNoBrowseTable;
|
||||
private bool _noSqlSoptSSHiddenColumns;
|
||||
|
||||
// SSS_WARNINGS_OFF
|
||||
private bool _noSqlCASSColumnKey;
|
||||
// SSS_WARNINGS_ON
|
||||
|
||||
// flags for unsupported Functions
|
||||
private bool _noSqlPrimaryKeys;
|
||||
|
||||
internal string DriverName {
|
||||
get {
|
||||
return _driverName;
|
||||
}
|
||||
set {
|
||||
_driverName = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal string DriverVersion {
|
||||
get {
|
||||
return _driverVersion;
|
||||
}
|
||||
set {
|
||||
_driverVersion = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasQuoteChar {
|
||||
// the value is set together with the QuoteChar (see set_QuoteChar);
|
||||
get {
|
||||
return _hasQuoteChar;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool HasEscapeChar {
|
||||
// the value is set together with the EscapeChar (see set_EscapeChar);
|
||||
get {
|
||||
return _hasEscapeChar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal string QuoteChar {
|
||||
get {
|
||||
return _quoteChar;
|
||||
}
|
||||
set {
|
||||
_quoteChar = value;
|
||||
_hasQuoteChar = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal char EscapeChar {
|
||||
get {
|
||||
return _escapeChar;
|
||||
}
|
||||
set {
|
||||
_escapeChar = value;
|
||||
_hasEscapeChar = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsV3Driver {
|
||||
get {
|
||||
return _isV3Driver;
|
||||
}
|
||||
set {
|
||||
_isV3Driver = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int SupportedSQLTypes {
|
||||
get {
|
||||
return _supportedSQLTypes;
|
||||
}
|
||||
set {
|
||||
_supportedSQLTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int TestedSQLTypes {
|
||||
get {
|
||||
return _testedSQLTypes;
|
||||
}
|
||||
set {
|
||||
_testedSQLTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal int RestrictedSQLBindTypes {
|
||||
get {
|
||||
return _restrictedSQLBindTypes;
|
||||
}
|
||||
set {
|
||||
_restrictedSQLBindTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal bool NoCurrentCatalog {
|
||||
get {
|
||||
return _noCurrentCatalog;
|
||||
}
|
||||
set {
|
||||
_noCurrentCatalog = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool NoConnectionDead {
|
||||
get {
|
||||
return _noConnectionDead;
|
||||
}
|
||||
set {
|
||||
_noConnectionDead = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal bool NoQueryTimeout {
|
||||
get {
|
||||
return _noQueryTimeout;
|
||||
}
|
||||
set {
|
||||
_noQueryTimeout = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool NoSqlSoptSSNoBrowseTable {
|
||||
get {
|
||||
return _noSqlSoptSSNoBrowseTable;
|
||||
}
|
||||
set {
|
||||
_noSqlSoptSSNoBrowseTable = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool NoSqlSoptSSHiddenColumns {
|
||||
get {
|
||||
return _noSqlSoptSSHiddenColumns;
|
||||
}
|
||||
set {
|
||||
_noSqlSoptSSHiddenColumns = value;
|
||||
}
|
||||
}
|
||||
|
||||
// SSS_WARNINGS_OFF
|
||||
internal bool NoSqlCASSColumnKey {
|
||||
get {
|
||||
return _noSqlCASSColumnKey;
|
||||
}
|
||||
set {
|
||||
_noSqlCASSColumnKey = value;
|
||||
}
|
||||
}
|
||||
// SSS_WARNINGS_ON
|
||||
|
||||
internal bool NoSqlPrimaryKeys {
|
||||
get {
|
||||
return _noSqlPrimaryKeys;
|
||||
}
|
||||
set {
|
||||
_noSqlPrimaryKeys = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionString.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
|
||||
internal sealed class OdbcConnectionString : DbConnectionOptions {
|
||||
// instances of this class are intended to be immutable, i.e readonly
|
||||
// used by pooling classes so it is much easier to verify correctness
|
||||
// when not worried about the class being modified during execution
|
||||
|
||||
private static class KEY {
|
||||
internal const string SaveFile = "savefile";
|
||||
}
|
||||
|
||||
private readonly string _expandedConnectionString;
|
||||
|
||||
internal OdbcConnectionString(string connectionString, bool validate) : base(connectionString, null, true) {
|
||||
if (!validate) {
|
||||
string filename = null;
|
||||
int position = 0;
|
||||
_expandedConnectionString = ExpandDataDirectories(ref filename, ref position);
|
||||
}
|
||||
if (validate || (null == _expandedConnectionString)) {
|
||||
// do not check string length if it was expanded because the final result may be shorter than the original
|
||||
if ((null != connectionString) && (ODBC32.MAX_CONNECTION_STRING_LENGTH < connectionString.Length)) { // MDAC 83536
|
||||
throw ODBC.ConnectionStringTooLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected internal override System.Security.PermissionSet CreatePermissionSet() {
|
||||
System.Security.PermissionSet permissionSet;
|
||||
if (ContainsKey(KEY.SaveFile)) {
|
||||
permissionSet = new NamedPermissionSet("FullTrust");
|
||||
}
|
||||
else {
|
||||
permissionSet = new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);
|
||||
permissionSet.AddPermission(new OdbcPermission(this));
|
||||
}
|
||||
return permissionSet;
|
||||
}
|
||||
|
||||
protected internal override string Expand() {
|
||||
if (null != _expandedConnectionString) {
|
||||
return _expandedConnectionString;
|
||||
}
|
||||
else {
|
||||
return base.Expand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,334 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcConnectionStringBuilder.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
[DefaultProperty("Driver")]
|
||||
[System.ComponentModel.TypeConverterAttribute(typeof(OdbcConnectionStringBuilder.OdbcConnectionStringBuilderConverter))]
|
||||
public sealed class OdbcConnectionStringBuilder : DbConnectionStringBuilder {
|
||||
|
||||
private enum Keywords { // must maintain same ordering as _validKeywords array
|
||||
// NamedConnection,
|
||||
Dsn,
|
||||
|
||||
Driver,
|
||||
}
|
||||
|
||||
private static readonly string[] _validKeywords;
|
||||
private static readonly Dictionary<string,Keywords> _keywords;
|
||||
|
||||
private string[] _knownKeywords;
|
||||
|
||||
private string _dsn = DbConnectionStringDefaults.Dsn;
|
||||
// private string _namedConnection = DbConnectionStringDefaults.NamedConnection;
|
||||
|
||||
private string _driver = DbConnectionStringDefaults.Driver;
|
||||
|
||||
static OdbcConnectionStringBuilder() {
|
||||
string[] validKeywords = new string[2];
|
||||
validKeywords[(int)Keywords.Driver] = DbConnectionStringKeywords.Driver;
|
||||
validKeywords[(int)Keywords.Dsn] = DbConnectionStringKeywords.Dsn;
|
||||
// validKeywords[(int)Keywords.NamedConnection] = DbConnectionStringKeywords.NamedConnection;
|
||||
_validKeywords = validKeywords;
|
||||
|
||||
Dictionary<string,Keywords> hash = new Dictionary<string,Keywords>(2, StringComparer.OrdinalIgnoreCase);
|
||||
hash.Add(DbConnectionStringKeywords.Driver, Keywords.Driver);
|
||||
hash.Add(DbConnectionStringKeywords.Dsn, Keywords.Dsn);
|
||||
// hash.Add(DbConnectionStringKeywords.NamedConnection, Keywords.NamedConnection);
|
||||
Debug.Assert(2 == hash.Count, "initial expected size is incorrect");
|
||||
_keywords = hash;
|
||||
}
|
||||
|
||||
public OdbcConnectionStringBuilder() : this((string)null) {
|
||||
}
|
||||
|
||||
public OdbcConnectionStringBuilder(string connectionString) : base(true) {
|
||||
if (!ADP.IsEmpty(connectionString)) {
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
}
|
||||
|
||||
public override object this[string keyword] {
|
||||
get {
|
||||
ADP.CheckArgumentNull(keyword, "keyword");
|
||||
Keywords index;
|
||||
if (_keywords.TryGetValue(keyword, out index)) {
|
||||
return GetAt(index);
|
||||
}
|
||||
else {
|
||||
return base[keyword];
|
||||
}
|
||||
}
|
||||
set {
|
||||
ADP.CheckArgumentNull(keyword, "keyword");
|
||||
if (null != value) {
|
||||
Keywords index;
|
||||
if (_keywords.TryGetValue(keyword, out index)) {
|
||||
switch(index) {
|
||||
case Keywords.Driver: Driver = ConvertToString(value); break;
|
||||
case Keywords.Dsn: Dsn = ConvertToString(value); break;
|
||||
// case Keywords.NamedConnection: NamedConnection = ConvertToString(value); break;
|
||||
default:
|
||||
Debug.Assert(false, "unexpected keyword");
|
||||
throw ADP.KeywordNotSupported(keyword);
|
||||
}
|
||||
}
|
||||
else {
|
||||
base[keyword] = value;
|
||||
ClearPropertyDescriptors();
|
||||
_knownKeywords = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Remove(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName(DbConnectionStringKeywords.Driver)]
|
||||
[ResCategoryAttribute(Res.DataCategory_Source)]
|
||||
[ResDescriptionAttribute(Res.DbConnectionString_Driver)]
|
||||
[RefreshPropertiesAttribute(RefreshProperties.All)]
|
||||
public string Driver {
|
||||
get { return _driver; }
|
||||
set {
|
||||
SetValue(DbConnectionStringKeywords.Driver, value);
|
||||
_driver = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName(DbConnectionStringKeywords.Dsn)]
|
||||
[ResCategoryAttribute(Res.DataCategory_NamedConnectionString)]
|
||||
[ResDescriptionAttribute(Res.DbConnectionString_DSN)]
|
||||
[RefreshPropertiesAttribute(RefreshProperties.All)]
|
||||
public string Dsn {
|
||||
get { return _dsn; }
|
||||
set {
|
||||
SetValue(DbConnectionStringKeywords.Dsn, value);
|
||||
_dsn = value;
|
||||
}
|
||||
}
|
||||
/*
|
||||
[DisplayName(DbConnectionStringKeywords.NamedConnection)]
|
||||
[ResCategoryAttribute(Res.DataCategory_NamedConnectionString)]
|
||||
[ResDescriptionAttribute(Res.DbConnectionString_NamedConnection)]
|
||||
[RefreshPropertiesAttribute(RefreshProperties.All)]
|
||||
[TypeConverter(typeof(NamedConnectionStringConverter))]
|
||||
public string NamedConnection {
|
||||
get { return _namedConnection; }
|
||||
set {
|
||||
SetValue(DbConnectionStringKeywords.NamedConnection, value);
|
||||
_namedConnection = value;
|
||||
}
|
||||
}
|
||||
*/
|
||||
public override ICollection Keys {
|
||||
get {
|
||||
string[] knownKeywords = _knownKeywords;
|
||||
if (null == knownKeywords) {
|
||||
knownKeywords = _validKeywords;
|
||||
|
||||
int count = 0;
|
||||
foreach(string keyword in base.Keys) {
|
||||
bool flag = true;
|
||||
foreach(string s in knownKeywords) {
|
||||
if (s == keyword) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (0 < count) {
|
||||
string[] tmp = new string[knownKeywords.Length + count];
|
||||
knownKeywords.CopyTo(tmp, 0);
|
||||
|
||||
int index = knownKeywords.Length;
|
||||
foreach(string keyword in base.Keys) {
|
||||
bool flag = true;
|
||||
foreach(string s in knownKeywords) {
|
||||
if (s == keyword) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
tmp[index++] = keyword;
|
||||
}
|
||||
}
|
||||
knownKeywords = tmp;
|
||||
}
|
||||
_knownKeywords = knownKeywords;
|
||||
}
|
||||
return new System.Data.Common.ReadOnlyCollection<string>(knownKeywords);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Clear() {
|
||||
base.Clear();
|
||||
for(int i = 0; i < _validKeywords.Length; ++i) {
|
||||
Reset((Keywords)i);
|
||||
}
|
||||
_knownKeywords = _validKeywords;
|
||||
}
|
||||
|
||||
public override bool ContainsKey(string keyword) {
|
||||
ADP.CheckArgumentNull(keyword, "keyword");
|
||||
return _keywords.ContainsKey(keyword) || base.ContainsKey(keyword);
|
||||
}
|
||||
|
||||
private static string ConvertToString(object value) {
|
||||
return DbConnectionStringBuilderUtil.ConvertToString(value);
|
||||
}
|
||||
|
||||
private object GetAt(Keywords index) {
|
||||
switch(index) {
|
||||
case Keywords.Driver: return Driver;
|
||||
case Keywords.Dsn: return Dsn;
|
||||
// case Keywords.NamedConnection: return NamedConnection;
|
||||
default:
|
||||
Debug.Assert(false, "unexpected keyword");
|
||||
throw ADP.KeywordNotSupported(_validKeywords[(int)index]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
protected override void GetProperties(Hashtable propertyDescriptors) {
|
||||
object value;
|
||||
if (TryGetValue(DbConnectionStringSynonyms.TRUSTEDCONNECTION, out value)) {
|
||||
bool trusted = false;
|
||||
if (value is bool) {
|
||||
trusted = (bool)value;
|
||||
}
|
||||
else if ((value is string) && !Boolean.TryParse((string)value, out trusted)) {
|
||||
trusted = false;
|
||||
}
|
||||
|
||||
if (trusted) {
|
||||
Attribute[] attributes = new Attribute[] {
|
||||
BrowsableAttribute.Yes,
|
||||
RefreshPropertiesAttribute.All,
|
||||
};
|
||||
DbConnectionStringBuilderDescriptor descriptor;
|
||||
descriptor = new DbConnectionStringBuilderDescriptor(DbConnectionStringSynonyms.TRUSTEDCONNECTION,
|
||||
this.GetType(), typeof(bool), false, attributes);
|
||||
descriptor.RefreshOnChange = true;
|
||||
propertyDescriptors[DbConnectionStringSynonyms.TRUSTEDCONNECTION] = descriptor;
|
||||
|
||||
if (ContainsKey(DbConnectionStringSynonyms.Pwd)) {
|
||||
descriptor = new DbConnectionStringBuilderDescriptor(DbConnectionStringSynonyms.Pwd,
|
||||
this.GetType(), typeof(string), true, attributes);
|
||||
propertyDescriptors[DbConnectionStringSynonyms.Pwd] = descriptor;
|
||||
}
|
||||
if (ContainsKey(DbConnectionStringSynonyms.UID)) {
|
||||
descriptor = new DbConnectionStringBuilderDescriptor(DbConnectionStringSynonyms.UID,
|
||||
this.GetType(), typeof(string), true, attributes);
|
||||
propertyDescriptors[DbConnectionStringSynonyms.UID] = descriptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
base.GetProperties(propertyDescriptors);
|
||||
}
|
||||
*/
|
||||
|
||||
public override bool Remove(string keyword) {
|
||||
ADP.CheckArgumentNull(keyword, "keyword");
|
||||
if (base.Remove(keyword)) {
|
||||
Keywords index;
|
||||
if (_keywords.TryGetValue(keyword, out index)) {
|
||||
Reset(index);
|
||||
}
|
||||
else {
|
||||
ClearPropertyDescriptors();
|
||||
_knownKeywords = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void Reset(Keywords index) {
|
||||
switch(index) {
|
||||
case Keywords.Driver:
|
||||
_driver = DbConnectionStringDefaults.Driver;
|
||||
break;
|
||||
case Keywords.Dsn:
|
||||
_dsn = DbConnectionStringDefaults.Dsn;
|
||||
break;
|
||||
// case Keywords.NamedConnection:
|
||||
// _namedConnection = DbConnectionStringDefaults.NamedConnection;
|
||||
// break;
|
||||
default:
|
||||
Debug.Assert(false, "unexpected keyword");
|
||||
throw ADP.KeywordNotSupported(_validKeywords[(int)index]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValue(string keyword, string value) {
|
||||
ADP.CheckArgumentNull(value, keyword);
|
||||
base[keyword] = value;
|
||||
}
|
||||
|
||||
public override bool TryGetValue(string keyword, out object value) {
|
||||
ADP.CheckArgumentNull(keyword, "keyword");
|
||||
Keywords index;
|
||||
if (_keywords.TryGetValue(keyword, out index)) {
|
||||
value = GetAt(index);
|
||||
return true;
|
||||
}
|
||||
return base.TryGetValue(keyword, out value);
|
||||
}
|
||||
|
||||
sealed internal class OdbcConnectionStringBuilderConverter : ExpandableObjectConverter {
|
||||
|
||||
// converter classes should have public ctor
|
||||
public OdbcConnectionStringBuilderConverter() {
|
||||
}
|
||||
|
||||
override public bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
|
||||
if (typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) {
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
override public object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
|
||||
if (destinationType == null) {
|
||||
throw ADP.ArgumentNull("destinationType");
|
||||
}
|
||||
if (typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor) == destinationType) {
|
||||
OdbcConnectionStringBuilder obj = (value as OdbcConnectionStringBuilder);
|
||||
if (null != obj) {
|
||||
return ConvertToInstanceDescriptor(obj);
|
||||
}
|
||||
}
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
|
||||
private System.ComponentModel.Design.Serialization.InstanceDescriptor ConvertToInstanceDescriptor(OdbcConnectionStringBuilder options) {
|
||||
Type[] ctorParams = new Type[] { typeof(string) };
|
||||
object[] ctorValues = new object[] { options.ConnectionString };
|
||||
System.Reflection.ConstructorInfo ctor = typeof(OdbcConnectionStringBuilder).GetConstructor(ctorParams);
|
||||
return new System.ComponentModel.Design.Serialization.InstanceDescriptor(ctor, ctorValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,177 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcDataAdapter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
[
|
||||
DefaultEvent("RowUpdated"),
|
||||
ToolboxItem("Microsoft.VSDesigner.Data.VS.OdbcDataAdapterToolboxItem, " + AssemblyRef.MicrosoftVSDesigner), // WebData 97832
|
||||
Designer("Microsoft.VSDesigner.Data.VS.OdbcDataAdapterDesigner, " + AssemblyRef.MicrosoftVSDesigner)
|
||||
]
|
||||
public sealed class OdbcDataAdapter : DbDataAdapter, IDbDataAdapter, ICloneable {
|
||||
|
||||
static private readonly object EventRowUpdated = new object();
|
||||
static private readonly object EventRowUpdating = new object();
|
||||
|
||||
private OdbcCommand _deleteCommand, _insertCommand, _selectCommand, _updateCommand;
|
||||
|
||||
public OdbcDataAdapter() : base() {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public OdbcDataAdapter(OdbcCommand selectCommand) : this() {
|
||||
SelectCommand = selectCommand;
|
||||
}
|
||||
|
||||
public OdbcDataAdapter(string selectCommandText, OdbcConnection selectConnection) : this() {
|
||||
SelectCommand = new OdbcCommand(selectCommandText, selectConnection);
|
||||
}
|
||||
|
||||
public OdbcDataAdapter(string selectCommandText, string selectConnectionString) : this() {
|
||||
OdbcConnection connection = new OdbcConnection(selectConnectionString);
|
||||
SelectCommand = new OdbcCommand(selectCommandText, connection);
|
||||
}
|
||||
|
||||
private OdbcDataAdapter(OdbcDataAdapter from) : base(from) {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
[
|
||||
DefaultValue(null),
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_DeleteCommand),
|
||||
Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
|
||||
]
|
||||
new public OdbcCommand DeleteCommand {
|
||||
get { return _deleteCommand; }
|
||||
set { _deleteCommand = value; }
|
||||
}
|
||||
|
||||
IDbCommand IDbDataAdapter.DeleteCommand {
|
||||
get { return _deleteCommand; }
|
||||
set { _deleteCommand = (OdbcCommand)value; }
|
||||
}
|
||||
|
||||
[
|
||||
DefaultValue(null),
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_InsertCommand),
|
||||
Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
|
||||
]
|
||||
new public OdbcCommand InsertCommand {
|
||||
get { return _insertCommand; }
|
||||
set { _insertCommand = value; }
|
||||
}
|
||||
|
||||
IDbCommand IDbDataAdapter.InsertCommand {
|
||||
get { return _insertCommand; }
|
||||
set { _insertCommand = (OdbcCommand)value; }
|
||||
}
|
||||
|
||||
[
|
||||
DefaultValue(null),
|
||||
ResCategoryAttribute(Res.DataCategory_Fill),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_SelectCommand),
|
||||
Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
|
||||
]
|
||||
new public OdbcCommand SelectCommand {
|
||||
get { return _selectCommand; }
|
||||
set { _selectCommand = value; }
|
||||
}
|
||||
|
||||
IDbCommand IDbDataAdapter.SelectCommand {
|
||||
get { return _selectCommand; }
|
||||
set { _selectCommand = (OdbcCommand)value; }
|
||||
}
|
||||
|
||||
[
|
||||
DefaultValue(null),
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_UpdateCommand),
|
||||
Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
|
||||
]
|
||||
new public OdbcCommand UpdateCommand {
|
||||
get { return _updateCommand; }
|
||||
set { _updateCommand = value; }
|
||||
}
|
||||
|
||||
IDbCommand IDbDataAdapter.UpdateCommand {
|
||||
get { return _updateCommand; }
|
||||
set { _updateCommand = (OdbcCommand)value; }
|
||||
}
|
||||
|
||||
[
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_RowUpdated),
|
||||
]
|
||||
public event OdbcRowUpdatedEventHandler RowUpdated {
|
||||
add {
|
||||
Events.AddHandler(EventRowUpdated, value); }
|
||||
remove {
|
||||
Events.RemoveHandler(EventRowUpdated, value); }
|
||||
}
|
||||
|
||||
[
|
||||
ResCategoryAttribute(Res.DataCategory_Update),
|
||||
ResDescriptionAttribute(Res.DbDataAdapter_RowUpdating),
|
||||
]
|
||||
public event OdbcRowUpdatingEventHandler RowUpdating {
|
||||
add {
|
||||
OdbcRowUpdatingEventHandler handler = (OdbcRowUpdatingEventHandler) Events[EventRowUpdating];
|
||||
|
||||
// MDAC 58177, 64513
|
||||
// prevent someone from registering two different command builders on the adapter by
|
||||
// silently removing the old one
|
||||
if ((null != handler) && (value.Target is OdbcCommandBuilder)) {
|
||||
OdbcRowUpdatingEventHandler d = (OdbcRowUpdatingEventHandler) ADP.FindBuilder(handler);
|
||||
if (null != d) {
|
||||
Events.RemoveHandler(EventRowUpdating, d);
|
||||
}
|
||||
}
|
||||
Events.AddHandler(EventRowUpdating, value);
|
||||
}
|
||||
remove {
|
||||
Events.RemoveHandler(EventRowUpdating, value); }
|
||||
}
|
||||
|
||||
|
||||
object ICloneable.Clone() {
|
||||
return new OdbcDataAdapter(this);
|
||||
}
|
||||
|
||||
override protected RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) {
|
||||
return new OdbcRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
|
||||
}
|
||||
|
||||
override protected RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) {
|
||||
return new OdbcRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
|
||||
}
|
||||
|
||||
override protected void OnRowUpdated(RowUpdatedEventArgs value) {
|
||||
OdbcRowUpdatedEventHandler handler = (OdbcRowUpdatedEventHandler) Events[EventRowUpdated];
|
||||
if ((null != handler) && (value is OdbcRowUpdatedEventArgs)) {
|
||||
handler(this, (OdbcRowUpdatedEventArgs) value);
|
||||
}
|
||||
base.OnRowUpdated(value);
|
||||
}
|
||||
|
||||
override protected void OnRowUpdating(RowUpdatingEventArgs value) {
|
||||
OdbcRowUpdatingEventHandler handler = (OdbcRowUpdatingEventHandler) Events[EventRowUpdating];
|
||||
if ((null != handler) && (value is OdbcRowUpdatingEventArgs)) {
|
||||
handler(this, (OdbcRowUpdatingEventArgs) value);
|
||||
}
|
||||
base.OnRowUpdating(value);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
2428b5e4901324f1ae0fa38fc81536ebb2c3cdb2
|
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcEnvironment.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
sealed internal class OdbcEnvironment {
|
||||
static private object _globalEnvironmentHandle;
|
||||
static private object _globalEnvironmentHandleLock = new object();
|
||||
|
||||
private OdbcEnvironment () {} // default const.
|
||||
|
||||
static internal OdbcEnvironmentHandle GetGlobalEnvironmentHandle() {
|
||||
OdbcEnvironmentHandle globalEnvironmentHandle = _globalEnvironmentHandle as OdbcEnvironmentHandle;
|
||||
if(null == globalEnvironmentHandle) {
|
||||
ADP.CheckVersionMDAC(true);
|
||||
|
||||
lock(_globalEnvironmentHandleLock) {
|
||||
globalEnvironmentHandle = _globalEnvironmentHandle as OdbcEnvironmentHandle;
|
||||
if(null == globalEnvironmentHandle) {
|
||||
globalEnvironmentHandle = new OdbcEnvironmentHandle();
|
||||
_globalEnvironmentHandle = globalEnvironmentHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return globalEnvironmentHandle;
|
||||
}
|
||||
|
||||
static internal void ReleaseObjectPool() {
|
||||
object globalEnvironmentHandle = Interlocked.Exchange(ref _globalEnvironmentHandle, null);
|
||||
if(null != globalEnvironmentHandle) {
|
||||
(globalEnvironmentHandle as OdbcEnvironmentHandle).Dispose(); // internally refcounted so will happen correctly
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,64 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcEnvironmentHandle.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
sealed internal class OdbcEnvironmentHandle : OdbcHandle {
|
||||
|
||||
// SxS: this method uses SQLSetEnvAttr to setup ODBC environment handle settings. Environment handle is safe in SxS.
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
|
||||
internal OdbcEnvironmentHandle() : base(ODBC32.SQL_HANDLE.ENV, null) {
|
||||
ODBC32.RetCode retcode;
|
||||
|
||||
//Set the expected driver manager version
|
||||
//
|
||||
retcode = UnsafeNativeMethods.SQLSetEnvAttr(
|
||||
this,
|
||||
ODBC32.SQL_ATTR.ODBC_VERSION,
|
||||
ODBC32.SQL_OV_ODBC3,
|
||||
ODBC32.SQL_IS.INTEGER);
|
||||
// ignore retcode
|
||||
|
||||
//Turn on connection pooling
|
||||
//Note: the env handle controls pooling. Only those connections created under that
|
||||
//handle are pooled. So we have to keep it alive and not create a new environment
|
||||
//for every connection.
|
||||
//
|
||||
retcode = UnsafeNativeMethods.SQLSetEnvAttr(
|
||||
this,
|
||||
ODBC32.SQL_ATTR.CONNECTION_POOLING,
|
||||
ODBC32.SQL_CP_ONE_PER_HENV,
|
||||
ODBC32.SQL_IS.INTEGER);
|
||||
|
||||
switch(retcode) {
|
||||
case ODBC32.RetCode.SUCCESS:
|
||||
case ODBC32.RetCode.SUCCESS_WITH_INFO:
|
||||
break;
|
||||
default:
|
||||
Dispose();
|
||||
throw ODBC.CantEnableConnectionpooling(retcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcError.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
|
||||
namespace System.Data.Odbc
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class OdbcError {
|
||||
//Data
|
||||
internal string _message;
|
||||
internal string _state;
|
||||
internal int _nativeerror;
|
||||
internal string _source;
|
||||
|
||||
internal OdbcError(string source, string message, string state, int nativeerror) {
|
||||
_source = source;
|
||||
_message = message;
|
||||
_state = state;
|
||||
_nativeerror= nativeerror;
|
||||
}
|
||||
|
||||
public string Message {
|
||||
get {
|
||||
return ((null != _message) ? _message : String.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public string SQLState {
|
||||
get {
|
||||
return _state;
|
||||
}
|
||||
}
|
||||
|
||||
public int NativeError {
|
||||
get {
|
||||
return _nativeerror;
|
||||
}
|
||||
}
|
||||
|
||||
public string Source {
|
||||
get {
|
||||
return ((null != _source) ? _source : String.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetSource (string Source) {
|
||||
_source = Source;
|
||||
}
|
||||
|
||||
override public string ToString() {
|
||||
return Message;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcErrorCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
|
||||
[Serializable]
|
||||
public sealed class OdbcErrorCollection : ICollection {
|
||||
private ArrayList _items = new ArrayList();
|
||||
|
||||
internal OdbcErrorCollection() {
|
||||
}
|
||||
|
||||
Object System.Collections.ICollection.SyncRoot {
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
bool System.Collections.ICollection.IsSynchronized {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return _items.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public OdbcError this[int i] {
|
||||
get {
|
||||
return (OdbcError)_items[i];
|
||||
}
|
||||
}
|
||||
|
||||
internal void Add(OdbcError error) {
|
||||
_items.Add(error);
|
||||
}
|
||||
|
||||
public void CopyTo (Array array, int i) {
|
||||
_items.CopyTo(array, i);
|
||||
}
|
||||
|
||||
public void CopyTo (OdbcError[] array, int i) {
|
||||
_items.CopyTo(array, i);
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator() {
|
||||
return _items.GetEnumerator();
|
||||
}
|
||||
|
||||
internal void SetSource (string Source) {
|
||||
foreach (object error in _items) {
|
||||
((OdbcError)error).SetSource(Source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcException.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.ComponentModel; //Component
|
||||
using System.Collections; //ICollection
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
[Serializable]
|
||||
public sealed class OdbcException : System.Data.Common.DbException {
|
||||
OdbcErrorCollection odbcErrors = new OdbcErrorCollection();
|
||||
|
||||
ODBC32.RETCODE _retcode; // DO NOT REMOVE! only needed for serialization purposes, because Everett had it.
|
||||
|
||||
static internal OdbcException CreateException(OdbcErrorCollection errors, ODBC32.RetCode retcode) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
foreach (OdbcError error in errors) {
|
||||
if (builder.Length > 0) {
|
||||
builder.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
builder.Append(Res.GetString(Res.Odbc_ExceptionMessage, ODBC32.RetcodeToString(retcode), error.SQLState, error.Message)); // MDAC 68337
|
||||
}
|
||||
OdbcException exception = new OdbcException(builder.ToString(), errors);
|
||||
return exception;
|
||||
}
|
||||
|
||||
internal OdbcException(string message, OdbcErrorCollection errors) : base(message) {
|
||||
odbcErrors = errors;
|
||||
HResult = HResults.OdbcException;
|
||||
}
|
||||
|
||||
// runtime will call even if private...
|
||||
private OdbcException(SerializationInfo si, StreamingContext sc) : base(si, sc) {
|
||||
_retcode = (ODBC32.RETCODE) si.GetValue("odbcRetcode", typeof(ODBC32.RETCODE));
|
||||
odbcErrors = (OdbcErrorCollection) si.GetValue("odbcErrors", typeof(OdbcErrorCollection));
|
||||
HResult = HResults.OdbcException;
|
||||
}
|
||||
|
||||
public OdbcErrorCollection Errors {
|
||||
get {
|
||||
return odbcErrors;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags=System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
|
||||
override public void GetObjectData(SerializationInfo si, StreamingContext context) {
|
||||
// MDAC 72003
|
||||
if (null == si) {
|
||||
throw new ArgumentNullException("si");
|
||||
}
|
||||
si.AddValue("odbcRetcode", _retcode, typeof(ODBC32.RETCODE));
|
||||
si.AddValue("odbcErrors", odbcErrors, typeof(OdbcErrorCollection));
|
||||
base.GetObjectData(si, context);
|
||||
}
|
||||
|
||||
// mdac bug 62559 - if we don't have it return nothing (empty string)
|
||||
override public string Source {
|
||||
get {
|
||||
if (0 < Errors.Count) {
|
||||
string source = Errors[0].Source;
|
||||
return ADP.IsEmpty(source) ? "" : source; // base.Source;
|
||||
}
|
||||
return ""; // base.Source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcFactory.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
public sealed class OdbcFactory : DbProviderFactory {
|
||||
|
||||
public static readonly OdbcFactory Instance = new OdbcFactory();
|
||||
|
||||
private OdbcFactory() {
|
||||
}
|
||||
|
||||
public override DbCommand CreateCommand() {
|
||||
return new OdbcCommand();
|
||||
}
|
||||
|
||||
public override DbCommandBuilder CreateCommandBuilder() {
|
||||
return new OdbcCommandBuilder();
|
||||
}
|
||||
|
||||
public override DbConnection CreateConnection() {
|
||||
return new OdbcConnection();
|
||||
}
|
||||
|
||||
public override DbConnectionStringBuilder CreateConnectionStringBuilder() {
|
||||
return new OdbcConnectionStringBuilder();
|
||||
}
|
||||
|
||||
public override DbDataAdapter CreateDataAdapter() {
|
||||
return new OdbcDataAdapter();
|
||||
}
|
||||
|
||||
public override DbParameter CreateParameter() {
|
||||
return new OdbcParameter();
|
||||
}
|
||||
|
||||
public override CodeAccessPermission CreatePermission(PermissionState state) {
|
||||
return new OdbcPermission(state);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,235 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OdbcHandle.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
|
||||
namespace System.Data.Odbc {
|
||||
|
||||
internal abstract class OdbcHandle : SafeHandle {
|
||||
|
||||
private ODBC32.SQL_HANDLE _handleType;
|
||||
private OdbcHandle _parentHandle;
|
||||
|
||||
protected OdbcHandle(ODBC32.SQL_HANDLE handleType, OdbcHandle parentHandle) : base(IntPtr.Zero, true) {
|
||||
|
||||
_handleType = handleType;
|
||||
|
||||
bool mustRelease = false;
|
||||
ODBC32.RetCode retcode = ODBC32.RetCode.SUCCESS;
|
||||
|
||||
// using ConstrainedRegions to make the native ODBC call and AddRef the parent
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
// validate handleType
|
||||
switch(handleType) {
|
||||
case ODBC32.SQL_HANDLE.ENV:
|
||||
Debug.Assert(null == parentHandle, "did not expect a parent handle");
|
||||
retcode = UnsafeNativeMethods.SQLAllocHandle(handleType, IntPtr.Zero, out base.handle);
|
||||
break;
|
||||
case ODBC32.SQL_HANDLE.DBC:
|
||||
case ODBC32.SQL_HANDLE.STMT:
|
||||
// must addref before calling native so it won't be released just after
|
||||
Debug.Assert(null != parentHandle, "expected a parent handle"); // safehandle can't be null
|
||||
parentHandle.DangerousAddRef(ref mustRelease);
|
||||
|
||||
retcode = UnsafeNativeMethods.SQLAllocHandle(handleType, parentHandle, out base.handle);
|
||||
break;
|
||||
// case ODBC32.SQL_HANDLE.DESC:
|
||||
default:
|
||||
Debug.Assert(false, "unexpected handleType");
|
||||
break;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (mustRelease) {
|
||||
switch(handleType) {
|
||||
case ODBC32.SQL_HANDLE.DBC:
|
||||
case ODBC32.SQL_HANDLE.STMT:
|
||||
if (IntPtr.Zero != base.handle) {
|
||||
// must assign _parentHandle after a handle is actually created
|
||||
// since ReleaseHandle will only call DangerousRelease if a handle exists
|
||||
_parentHandle = parentHandle;
|
||||
}
|
||||
else {
|
||||
// without a handle, ReleaseHandle may not be called
|
||||
parentHandle.DangerousRelease();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Bid.TraceSqlReturn("<odbc.SQLAllocHandle|API|ODBC|RET> %08X{SQLRETURN}\n", retcode);
|
||||
|
||||
if((ADP.PtrZero == base.handle) || (ODBC32.RetCode.SUCCESS != retcode)) {
|
||||
//
|
||||
throw ODBC.CantAllocateEnvironmentHandle(retcode);
|
||||
}
|
||||
}
|
||||
|
||||
internal OdbcHandle(OdbcStatementHandle parentHandle, ODBC32.SQL_ATTR attribute) : base(IntPtr.Zero, true) {
|
||||
Debug.Assert((ODBC32.SQL_ATTR.APP_PARAM_DESC == attribute) || (ODBC32.SQL_ATTR.APP_ROW_DESC == attribute), "invalid attribute");
|
||||
_handleType = ODBC32.SQL_HANDLE.DESC;
|
||||
|
||||
int cbActual;
|
||||
ODBC32.RetCode retcode;
|
||||
bool mustRelease = false;
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try {
|
||||
// must addref before calling native so it won't be released just after
|
||||
parentHandle.DangerousAddRef(ref mustRelease);
|
||||
|
||||
retcode = parentHandle.GetStatementAttribute(attribute, out base.handle, out cbActual);
|
||||
}
|
||||
finally {
|
||||
if (mustRelease) {
|
||||
if (IntPtr.Zero != base.handle) {
|
||||
// must call DangerousAddRef after a handle is actually created
|
||||
// since ReleaseHandle will only call DangerousRelease if a handle exists
|
||||
_parentHandle = parentHandle;
|
||||
}
|
||||
else {
|
||||
// without a handle, ReleaseHandle may not be called
|
||||
parentHandle.DangerousRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ADP.PtrZero == base.handle) {
|
||||
throw ODBC.FailedToGetDescriptorHandle(retcode);
|
||||
}
|
||||
// no info-message handle on getting a descriptor handle
|
||||
}
|
||||
|
||||
internal ODBC32.SQL_HANDLE HandleType {
|
||||
get {
|
||||
return _handleType;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsInvalid {
|
||||
get {
|
||||
// we should not have a parent if we do not have a handle
|
||||
return (IntPtr.Zero == base.handle);
|
||||
}
|
||||
}
|
||||
|
||||
override protected bool ReleaseHandle() {
|
||||
// NOTE: The SafeHandle class guarantees this will be called exactly once and is non-interrutible.
|
||||
IntPtr handle = base.handle;
|
||||
base.handle = IntPtr.Zero;
|
||||
|
||||
if (IntPtr.Zero != handle) {
|
||||
ODBC32.SQL_HANDLE handleType = HandleType;
|
||||
|
||||
switch (handleType) {
|
||||
case ODBC32.SQL_HANDLE.DBC:
|
||||
// Disconnect happens in OdbcConnectionHandle.ReleaseHandle
|
||||
case ODBC32.SQL_HANDLE.ENV:
|
||||
case ODBC32.SQL_HANDLE.STMT:
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLFreeHandle(handleType, handle);
|
||||
Bid.TraceSqlReturn("<odbc.SQLFreeHandle|API|ODBC|RET> %08X{SQLRETURN}\n", retcode);
|
||||
break;
|
||||
|
||||
case ODBC32.SQL_HANDLE.DESC:
|
||||
// nothing to free on the handle
|
||||
break;
|
||||
|
||||
// case 0: ThreadAbortException setting handle before HandleType
|
||||
default:
|
||||
Debug.Assert(ADP.PtrZero == handle, "unknown handle type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we ended up getting released, then we have to release
|
||||
// our reference on our parent.
|
||||
OdbcHandle parentHandle = _parentHandle;
|
||||
_parentHandle = null;
|
||||
if (null != parentHandle) {
|
||||
parentHandle.DangerousRelease();
|
||||
parentHandle = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetDiagnosticField (out string sqlState) {
|
||||
short cbActual;
|
||||
// ODBC (MSDN) documents it expects a buffer large enough to hold 5(+L'\0') unicode characters
|
||||
StringBuilder sb = new StringBuilder(6);
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetDiagFieldW(
|
||||
HandleType,
|
||||
this,
|
||||
(short)1,
|
||||
ODBC32.SQL_DIAG_SQLSTATE,
|
||||
sb,
|
||||
checked((short)(2*sb.Capacity)), // expects number of bytes, see \\kbinternal\kb\articles\294\1\69.HTM
|
||||
out cbActual);
|
||||
ODBC.TraceODBC(3, "SQLGetDiagFieldW", retcode);
|
||||
if ((retcode == ODBC32.RetCode.SUCCESS) || (retcode == ODBC32.RetCode.SUCCESS_WITH_INFO)) {
|
||||
sqlState = sb.ToString();
|
||||
}
|
||||
else {
|
||||
sqlState = ADP.StrEmpty;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetDiagnosticRecord(short record, out string sqlState, StringBuilder message, out int nativeError, out short cchActual) {
|
||||
// ODBC (MSDN) documents it expects a buffer large enough to hold 4(+L'\0') unicode characters
|
||||
StringBuilder sb = new StringBuilder(5);
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetDiagRecW(HandleType, this, record, sb, out nativeError, message, checked((short)message.Capacity), out cchActual);
|
||||
ODBC.TraceODBC(3, "SQLGetDiagRecW", retcode);
|
||||
|
||||
if ((retcode == ODBC32.RetCode.SUCCESS) || (retcode == ODBC32.RetCode.SUCCESS_WITH_INFO)) {
|
||||
sqlState = sb.ToString();
|
||||
}
|
||||
else {
|
||||
sqlState = ADP.StrEmpty;
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
sealed internal class OdbcDescriptorHandle : OdbcHandle {
|
||||
|
||||
internal OdbcDescriptorHandle(OdbcStatementHandle statementHandle, ODBC32.SQL_ATTR attribute) : base(statementHandle, attribute) {
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode GetDescriptionField(int i, ODBC32.SQL_DESC attribute, CNativeBuffer buffer, out int numericAttribute) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLGetDescFieldW(this, checked((short)i), attribute, buffer, buffer.ShortLength, out numericAttribute);
|
||||
ODBC.TraceODBC(3, "SQLGetDescFieldW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode SetDescriptionField1(short ordinal, ODBC32.SQL_DESC type, IntPtr value) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLSetDescFieldW(this, ordinal, type, value, 0);
|
||||
ODBC.TraceODBC(3, "SQLSetDescFieldW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
internal ODBC32.RetCode SetDescriptionField2(short ordinal, ODBC32.SQL_DESC type, HandleRef value) {
|
||||
ODBC32.RetCode retcode = UnsafeNativeMethods.SQLSetDescFieldW(this, ordinal, type, value, 0);
|
||||
ODBC.TraceODBC(3, "SQLSetDescFieldW", retcode);
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user