SQLGetInfo - как использовать эту функцию

Я разработал приложение c#, которое подключается ко многим типам серверов баз данных,таких как Sql,Oracle, Mysql и т. д..Соединение было установлено с помощью ODBC для.

Мне нужно найти тип сервера (тип СУБД), для которого было установлено соединение, так как пользователь вводит только DSN имя.

после нескольких часов серфинга я обнаружил, что мое требование возможно только через эту функцию функции sqlgetinfo.Но я не знаю как чтобы справиться с этим в C#.

даже проверили эту link1 и.

из приведенной выше ссылки я обнаружил, что ODBC API дает только имя базы данных и Имя Источника Данных.Но мне нужно найти тип Datatbase, например, является ли это соединение SQL или соединение Oracle или mySqlConnection.

можно ли получить тип СУБД из имени DSN..?

примечание: Я не хочу читать его из параметра реестра.Я пробовал это. и это работает, но у меня проблемы с разрешением..!

3 ответов


это абсолютно сделает трюк. Вот моя реализация для подключения функции OdbcConnection GetInfoStringUnhandled. Боже, мы любим отражение,Я знаю, что Я легенда ;)

public enum SQL_INFO
{
    DATA_SOURCE_NAME,
    DRIVER_NAME,
    DRIVER_VER,
    ODBC_VER,
    SERVER_NAME,
    SEARCH_PATTERN_ESCAPE,
    DBMS_NAME,
    DBMS_VER,
    IDENTIFIER_CASE,
    IDENTIFIER_QUOTE_CHAR,
    CATALOG_NAME_SEPARATOR,
    DRIVER_ODBC_VER,
    GROUP_BY,
    KEYWORDS,
    ORDER_BY_COLUMNS_IN_SELECT,
    QUOTED_IDENTIFIER_CASE,
    SQL_OJ_CAPABILITIES_30,
    SQL_SQL92_RELATIONAL_JOIN_OPERATORS,
    SQL_OJ_CAPABILITIES_20

}

public static string GetInfoStringUnhandled(OdbcConnection ocn, SQL_INFO info)
{
    MethodInfo GetInfoStringUnhandled = ocn.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).First(c => c.Name == "GetInfoStringUnhandled");
    ParameterInfo SQL_INFO =
        GetInfoStringUnhandled.GetParameters()
            .First(c => (c.ParameterType.ToString() == "System.Data.Odbc.ODBC32+SQL_INFO"));
    Array EnumValues = SQL_INFO.ParameterType.GetEnumValues();
    foreach (var enumval in EnumValues) {
        if (enumval.ToString() == info.ToString()) {
            return Convert.ToString(GetInfoStringUnhandled.Invoke(ocn, new object[] { enumval }));
        }
    }
    return string.Empty;
}

private static void Main(string[] args)
{
    OdbcConnection ocn = new OdbcConnection("DSN=GENESIS");
    ocn.Open();
    Console.WriteLine(GetInfoStringUnhandled(ocn, SQL_INFO.DBMS_VER) + " " +
                      GetInfoStringUnhandled(ocn, SQL_INFO.DBMS_NAME));
}

лучшая документация, которую я нашел, объясняя 47 возможностей использования SQLGetInfo здесь https://mariadb.com/kb/en/sql-99/sqlgetinfo/

тем не менее, OdbcConnection только что интегрировал перечисление с 19 возможностями. Этот ниже приведено разобранное перечисление SQL_INFO системы.Данные.интерфейс ODBC.Библиотекой odbc32:

public enum SQL_INFO : ushort
{
    DATA_SOURCE_NAME = (ushort)2,
    DRIVER_NAME = (ushort)6,
    DRIVER_VER = (ushort)7,
    ODBC_VER = (ushort)10,
    SERVER_NAME = (ushort)13,
    SEARCH_PATTERN_ESCAPE = (ushort)14,
    DBMS_NAME = (ushort)17,
    DBMS_VER = (ushort)18,
    IDENTIFIER_CASE = (ushort)28,
    IDENTIFIER_QUOTE_CHAR = (ushort)29,
    CATALOG_NAME_SEPARATOR = (ushort)41,
    DRIVER_ODBC_VER = (ushort)77,
    GROUP_BY = (ushort)88,
    KEYWORDS = (ushort)89,
    ORDER_BY_COLUMNS_IN_SELECT = (ushort)90,
    QUOTED_IDENTIFIER_CASE = (ushort)93,
    SQL_OJ_CAPABILITIES_30 = (ushort)115,
    SQL_SQL92_RELATIONAL_JOIN_OPERATORS = (ushort)161,
    SQL_OJ_CAPABILITIES_20 = (ushort)65003
}

как вы видите, вы можете просто вызвать метод GetInfoStringUnhandled с (ushort) литым целым числом необходимой вам информации. Вот пример:

public static string GetInfoStringUnhandled(OdbcConnection ocn, ushort info)
{
    MethodInfo GetInfoStringUnhandled = ocn.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).First(c => c.Name == "GetInfoStringUnhandled");
    return Convert.ToString(GetInfoStringUnhandled.Invoke(ocn, new object[] { (ushort)info }));            
}

public static void Main(string[] args)
{
    OdbcConnection ocn = new OdbcConnection("DSN=GENESIS");
    ocn.Open();
    Console.WriteLine(GetInfoStringUnhandled(ocn, (ushort)10003)); //SQL_CATALOG_NAME returns Y
}

короткий ответ: не надо. Вместо этого очень старайтесь найти управляемые эквиваленты. Нет документированного способа получить этот дескриптор.

ответ: параметр InfoType функции SQLGetInfo имеет 47 возможных значений. Ref. Шаблон регулярных выражений для указанных идентификаторов можно получить следующим образом:

DataTable dt = connection.GetSchema(DbMetaDataCollectionNames.DataSourceInformation); 
string quotedIdentifierPattern = (string)dt.Rows[0][DbMetaDataColumnNames.QuotedIdentifierPattern];

это позволит вам распознавать, но не создавать кавычки идентификаторов. Можно с уверенностью предположить, что символ цитаты действительно один символ, хотя, так что вы можете получить его, просто делая:

Regex.Unescape(quotedIdentifierPattern)[0];

(The .Раскодировал() в кавычки может быть особенного regexen и отсюда сбежал.)

большинство других применений для SQLInfo () можно аналогично решить.Метод getschema(). Если вы абсолютно, положительно должны использовать SQLGetInfo () для чего-то, я рекомендую использование частных методов .GetInfoInt16Unhandled(), .GetInfoInt32Unhandled() и ..GetInfoStringUnhandled() on OdbcConnection через отражение. Это предметом ломая без предупреждение, однако.

вы можете получить внутреннюю ручку через личное .ConnectionHandle член, но это одинаково подвержено ломке и гораздо менее удобно (потому что вы также должны написать весь неуправляемый код взаимодействия).

использовать помощью ILSpy или отражатель чтобы получить больше детали реализации. Обратное проектирование внутренностей может во многих кейсы указывают на полностью управляемое решение. Ref.


или построить на этом пример код для обнаружения версии с помощью различных команд, например

MySQL: "SELECT version ()";
Oracle: "выберите @@version, @@version_comment из dual";
SQLServer: "выберите @@version";

пример кода MSDN:

using System;
using System.Data;

namespace IDbConnectionSample {
   class Program {
      static void Main(string[] args) {
         IDbConnection connection;

         // First use a SqlClient connection
         connection = new System.Data.SqlClient.SqlConnection(@"Server=(localdb)\V11.0");
         Console.WriteLine("SqlClient\r\n{0}", GetServerVersion(connection));
         connection = new System.Data.SqlClient.SqlConnection(@"Server=(local);Integrated Security=true");
         Console.WriteLine("SqlClient\r\n{0}", GetServerVersion(connection));

         // Call the same method using ODBC 
         // NOTE: LocalDB requires the SQL Server 2012 Native Client ODBC driver
         connection = new System.Data.Odbc.OdbcConnection(@"Driver={SQL Server Native Client 11.0};Server=(localdb)\v11.0");
         Console.WriteLine("ODBC\r\n{0}", GetServerVersion(connection));
         connection = new System.Data.Odbc.OdbcConnection(@"Driver={SQL Server Native Client 11.0};Server=(local);Trusted_Connection=yes");
         Console.WriteLine("ODBC\r\n{0}", GetServerVersion(connection));

         // Call the same method using OLE DB
         connection = new System.Data.OleDb.OleDbConnection(@"Provider=SQLNCLI11;Server=(localdb)\v11.0;Trusted_Connection=yes;");
         Console.WriteLine("OLE DB\r\n{0}", GetServerVersion(connection));
         connection = new System.Data.OleDb.OleDbConnection(@"Provider=SQLNCLI11;Server=(local);Trusted_Connection=yes;");
         Console.WriteLine("OLE DB\r\n{0}", GetServerVersion(connection));
         }

      public static string GetServerVersion(IDbConnection connection) {
         // Ensure that the connection is opened (otherwise executing the command will fail)
         ConnectionState originalState = connection.State;
         if (originalState != ConnectionState.Open)
            connection.Open();
         try {
            // Create a command to get the server version 
            IDbCommand command = connection.CreateCommand();
            command.CommandText = "SELECT @@version"; //<- HERE  
            //try out the different commands by passing the CommandText as a parameter
            return (string)command.ExecuteScalar();
         }
         finally {
            // Close the connection if that's how we got it 
            if (originalState == ConnectionState.Closed)
               connection.Close();
         }
      }
   }
}

или вы могли бы сделать что-то, как другие предлагают, с немного больше элегантности.

Примечание: это задание копирования / вставки на ответ @FabianStern-кредит автору. Я просто сделал его менее процедурным и более ортодоксальным, поскольку я не мог выдержать каскадную попытку поймать):

protected static DBType GetDBType(string odbcConnStr)
{
 var dbType = DBType.UNSUPPORTED;
 try
 {
  using (var cn = new OdbcConnection(odbcConnStr))
  {
    if (cn.State != ConnectionState.Open) cn.Open();
    dbType = GetDbType(cn, dbType)
    if (dbType > 0) return dbType;

    var sqlVersionQuery = "SELECT version()"; 
    dbType = GetDbType(cn, sqlVersionQuery, DBType.MYSQL)
    if (dbType > 0) return dbType;

    sqlVersionQuery = "SELECT @@version, @@version_comment FROM dual"; 
    dbType = GetDbType(cn, sqlVersionQuery, DBType.Oracle)
    if (dbType > 0) return dbType;

    sqlVersionQuery = "SELECT @@version"; 
    dbType = GetDbType(cn, sqlVersionQuery, DBType.MSSQL)
    if (dbType > 0) return dbType;
  }
 }
 catch(Exception connEx) { }
 return dbType;
}

public enum DBType
{
    UNSUPPORTED = 0,
    MYSQL = 1,
    ORACLE = 2,
    MSSQL = 3,
    JET = 4
}

private static DBType GetDBType(OdbcConnection cn, DBType dbType)
{
  try
  {
    if (cn.Driver == "odbcjt32.dll") dbType = DBType.JET;
  }
  catch(Exception ex) { }
  return dbType;
}

private static DBType GetDbType(OdbcConnection cn, string sqlVersionQuery, DBType dbType)
{
  try
  {
  using (var cmd = cn.CreateCommand()) {
  cmd.CommandText = sqlVersionQuery;
    try
    {
       using (var reader = cmd.ExecuteReader()) 
       {
           if (reader.HasRows) return dbType;
       }
    }
    catch (Exception ex) { }
  }}
  catch (Exception cmdEx) { }           
  }
 return dbType;
}

вы пытались разобрать .Свойство драйвера OdbcConnection ? Он покажет вам используемый драйвер оболочки базы данных для подключения. Вы можете найти эти сопоставления также в реестре по адресу HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ODBC

иногда это просто .имя dll (например, для драйвера Microsoft Excel), но это может дать вам подсказку.

вы также можете выполнять определенные команды базы данных для получения версии базы данных с сервера следующим образом:

   static void Main(string[] args)
    {
        var cn = new OdbcConnection("DSN=mysql1");
        Console.WriteLine("DBType: {0}", GetDbType(cn));
        Console.Read();
    }

    public enum DbType
    {
        UNSUPPORTED = 0,
        MYSQL = 1,
        ORACLE = 2,
        MSSQL = 3,
        POSTGRESQL = 4,
        JET = 5
    }

    public static DbType GetDbType(OdbcConnection cn)
    {
        DbType t = DbType.UNSUPPORTED;
            try
            {
                if (cn.State != ConnectionState.Open) cn.Open();

                if (cn.Driver == "odbcjt32.dll")
                {
                    return DbType.JET;
                }

                var cmd = cn.CreateCommand();
                string outstring = "";
                cmd.CommandText = "SELECT * FROM v$version";
                try
                {
                    var reader = cmd.ExecuteReader();
                    if (reader.HasRows)
                    {
                        reader.Read();
                        outstring = String.Format("{0}", reader.GetString(0));

                    }
                }
                catch (Exception)
                {
                    cmd = cn.CreateCommand();
                    cmd.CommandText = "SELECT @@version, @@version_comment FROM dual";
                    try
                    {
                        var reader = cmd.ExecuteReader();
                        if (reader.HasRows)
                        {
                            reader.Read();
                            outstring = String.Format("{0} {1}", reader.GetString(0), reader.GetString(1));

                        }
                    }
                    catch (Exception)
                    {
                        cmd = cn.CreateCommand();
                        cmd.CommandText = "SELECT @@version";
                        try
                        {
                            var reader = cmd.ExecuteReader();
                            if (reader.HasRows)
                            {
                                reader.Read();
                                outstring = String.Format("{0}", reader.GetString(0));

                            }
                        }
                        catch (Exception)
                        {
                            cmd = cn.CreateCommand();
                            cmd.CommandText = "SELECT version()";
                            try
                            {
                                var reader = cmd.ExecuteReader();
                                if (reader.HasRows)
                                {
                                    reader.Read();
                                    outstring = String.Format("{0}", reader.GetString(0));

                                }
                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }

                outstring = outstring.ToUpper();

                if (outstring.Contains("MYSQL"))
                {
                    t = DbType.MYSQL;
                }
                else if (outstring.Contains("ORACLE"))
                {
                    t = DbType.ORACLE;
                }
                else if (outstring.Contains("SQL SERVER"))
                {
                    t = DbType.MSSQL;
                }
                else if (outstring.Contains("POSTGRESQL"))
                {
                    t = DbType.POSTGRESQL;
                }


            }
            catch (Exception E)
            {

            }
        return t;

    }