Приложения ADO могут использовать поставщика OLE DB для SQLOLEDB, который входит в состав Windows, если им не требуются какие-либо функции SQL Server 2005 или более поздней версии.

вопрос является частью серии ошибок в драйвере Microsoft ODBC:

Драйвер ODBC не может вызвать ошибки; но вместо этого подавляет ихЧтение столбцов не по порядку возвращает неверные результатыНевозможно выполнить хранимую процедуру, которая является SYNONYM

Microsoft заявила, что они не будут исправлять эти ошибки в драйвере ODBC.

Укороченная версия

Если я читаюуникальный идентификатор значения вВЫБРАТЬ порядок, мне вернули правильные значения:

ColumnB: (прочитайте правильное значение)ColumnC (прочитайте правильное значение)

Если я читаю значения столбца uniqueidentifier вне порядка выбора, более ранние столбцы ничего не возвращают (и иногда мусор):

ColumnC (прочитайте правильное значение)ColumnB (возвращается пустым)

Я проверил это на:

Microsoft SQL Azure (окончательная первоначальная версия) - 12.0.2000.8Microsoft SQL Server 2012 (SP3)Microsoft SQL Server 2008 R2 (SP2)Microsoft SQL Server 2005 - 9.00.5000.00 (Intel X86)Windows 10Windows 7Виндоус виста

редактироватьПримеры кода для:

C #(приложение командной строки)Delphi(приложение командной строки)Javascript(командная строкаcscript)Html + Javascript(Только Internet Explorer)Фон

С участиемобъявление об устаревании драйверов OleDbЯ хотел проверить с помощью драйверов ODBC для SQL Server. Когда я меняю соединение, чтобы использовать один из драйверов ODBC для SQL Server (например, "{SQL Server}"), и выполняю ту же инструкцию SQL.

Обновление - не рекомендуется: Шесть лет спустя Microsoftобъявил об устаревании драйвера OLE DB для SQL Server. (архив)

Ранее Microsoftобъявил об устаревании поставщика Microsoft OLE DB для SQL Server, часть собственного клиента SQL Server (SNAC). В то время это решение было принято, чтобы попытаться придать больше простоты истории разработчиков о разработке собственного программного обеспечения для Windows, когда мы перешли в облачную эру с базой данных SQL Azure, и попытаться использовать сходство JDBC и ODBC для разработчиков. Однако в ходе последующих проверок было установлено, что устаревание является ошибкой, поскольку существенные сценарии в SQL Server по-прежнему зависят от OLE DB, и их изменение может нарушить некоторые существующие сценарии заказчика.

Имея это в виду, мы решилинедооценивать OLE DB и выпустить новую версиюпервый квартал календарного года 2018 Март 2018 г.

Я выдаю запрос для трех фиксированных столбцов:

SELECT
   CAST('Hello' AS varchar(max)) AS ColumnA,
   CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB,
   CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC

Это означает, что есть три столбца:

| ColumnA            | ColumnB                              | ColumnC                              |
| varchar(max)       | uniqueidentifier                     | uniqueidentifier                     |
|--------------------|--------------------------------------|--------------------------------------|
| 'Hello'            | C6705EDE-CE58-4AB9-81BE-679AC1E75DE6 | 2466C151-88EC-40C0-B091-25B6BD74070C |

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

Я использую ADO (родной COM) иSQL Server Драйвер ODBC для подключения к SQL Server:

Provider=MSDASQL;Driver={SQL Server};Server={vader};Database=master;Trusted_Connection=Yes;
Чтение столбца C сначала приводит к тому, что ColumnB становится пустым

В этом MRCE я только читаю значения двухuniqueidentifier колонны.

recordset.Fields['ColumnB'].Value;
recordset.Fields['ColumnC'].Value;

и если я прочитал две колонкив этой последовательности, значения получаются правильными:

ColumnB: "C6705EDE-CE58-4AB9-81BE-679AC1E75DE6" (Тип ВариантаVT_BSTR)ColumnC: "2466C151-88EC-40C0-B091-25B6BD74070C" (Тип ВариантаVT_BSTR)

Но если я читаю значения столбца в другом порядке:

ColumnC: "2466C151-88EC-40C0-B091-25B6BD74070C" (Тип ВариантаVT_BSTR)ColumnB: (empty) (Тип ВариантаVT_EMPTY)Пример минимального кода (C #)
using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            TestIt();
        }

        private static void TestIt()
        {
            String serverName = "vader";
            String CRLF = "\r\n";

            String connectionString = "Provider=MSDASQL;Driver={SQL Server};Server={" + serverName + "};Database=master;Trusted_Connection=Yes;";
            WriteLn("ConnectionString: " + connectionString);
            WriteLn("");

            Int32 adOpenForwardOnly = 0;
            Int32 adLockReadOnly = 1;
            Int32 adCmdText = 1;

            dynamic rs = CreateOleObject("ADODB.Recordset");

            String sql = "SELECT " + CRLF +
                " CAST('Hello' AS varchar(max)) AS ColumnA, " + CRLF +
                " CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB," + CRLF +
                " CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC";

            WriteLn("Command text:");
            WriteLn(sql);
           , WriteLn("");

            WriteLn("Executing query");
            rs.open(sql, connectionString, adOpenForwardOnly, adLockReadOnly, adCmdText);
            WriteLn("Query complete");

            if (rs.EOF) return; //just to shut people up

            var columnC = rs("ColumnC").Value;
            var columnB = rs("ColumnB").Value;

            WriteLn("ColumnB: " + columnB);
            WriteLn("ColumnC: " + columnC);
        }

        private static dynamic CreateOleObject(string progID)
        {
            Type comType = Type.GetTypeFromProgID(progID);
            var instance = Activator.CreateInstance(comType);

            return instance;
        }

        private static void WriteLn(string v)
        {
            Console.WriteLine(v);
        }
    }
}

с результатами:

ConnectionString: Provider=MSDASQL;Driver={SQL Server};Server={vader};Database=master;Trusted_Connection=Yes;

Command text:
SELECT
 CAST('Hello' AS varchar(max)) AS ColumnA,
 CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB,
 CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC

Executing query
Query complete
ColumnB:
ColumnC: {2466C151-88EC-40C0-B091-25B6BD74070C}
Пример минимального кода (Delphi)
program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  ADOInt,
  ComObj,
    ActiveX;

function DataTypeEnumToStr(t: DataTypeEnum): string;
begin
    case t of
    adEmpty: Result := 'adEmpty';
    adSmallInt: Result := 'adSmallInt';
    adInteger: Result := 'adInteger';
    adTinyInt: Result := 'adTinyInt';
    adBigInt: Result := 'adBigInt';
    adUnsignedTinyInt: Result := 'adUnsignedTinyInt';
    adUnsignedSmallInt: Result := 'adUnsignedSmallInt';
    adUnsignedInt: Result := 'adUnsignedInt';
    adUnsignedBigInt: Result := 'adUnsignedBigInt';
    adSingle: Result := 'adSingle';
    adDouble: Result := 'adDouble';
    adCurrency: Result := 'adCurrency';
    adDecimal: Result := 'adDecimal';
    adNumeric: Result := 'adNumeric';
    adBoolean: Result := 'adBoolean';
    adError: Result := 'adError';
    adUserDefined: Result := 'adUserDefined';
    adVariant: Result := 'adVariant';
    adIDispatch: Result := 'adIDispatch';
    adIUnknown: Result := 'adIUnknown';
    adGUID: Result := 'adGUID';
    adDate: Result := 'adDate';
    adDBDate: Result := 'adDBDate';
    adDBTime: Result := 'adDBTime';
    adDBTimeStamp: Result := 'adDBTimeStamp';
    adBSTR: Result := 'adBSTR';
    adChar: Result := 'adChar';
    adVarChar: Result := 'adVarChar';
    adLongVarChar: Result := 'adLongVarChar';
    adWChar: Result := 'adWChar';
    adVarWChar: Result := 'adVarWChar';
    adLongVarWChar: Result := 'adLongVarWChar';
    adBinary: Result := 'adBinary';
    adVarBinary: Result := 'adVarBinary';
    adLongVarBinary: Result := 'adLongVarBinary';
    adChapter: Result := 'adChapter';
    adFileTime: Result := 'adFileTime';
    adDBFileTime: Result := 'adDBFileTime';
    adPropVariant: Result := 'adPropVariant';
    adVarNumeric: Result := 'adVarNumeric';
    adArray: Result := 'adArray';
    else
        Result := IntToStr(t);
    end;
end;

procedure TestLoadingGUID;
var
    connectionString: string;
    sql: string;
    rs: _Recordset;
    s: string;
    guid: TGUID;
    i: Integer;
    fld: Field;

    function DumpField(const FieldName: string): string;
    var
        sValue: string;
        vt: TVarType;
        value: OleVariant;
    begin
        WriteLn('Reading '+FieldName+' column');
        value := rs.Fields[FieldName].Value;

        sValue := value;
        vt := TVarData(value).VType;
        WriteLn('   VType: '+IntToStr(vt));
        WriteLn('   Value: "'+sValue+'" (as string)');
        WriteLn('');
    end;

begin
{
    Tested:
        Windows 10
        Windows 7

        Microsoft SQL Server 2012 (SP3)
        Microsoft SQL Server 2008 R2 (SP2)
        Microsoft SQL Server 2005 - 9.00.5000.00 (Intel X86)
}

    Write('Enter name of server to connect to (leave blank for VADER): ');
    ReadLn(s);

    if s = '' then
        s := 'vader';

    connectionString := 'Provider=MSDASQL;Driver={SQL Server};Server={'+s+'};Database=master;Trusted_Connection=Yes;';
    WriteLn('ConnectionString: '+connectionString);
    WriteLn;


//  sql := 'SELECT CAST(NULL AS varchar(max)) AS ColumnA, newid() AS ColumnB, newid() as ColumnC';
    sql := 'SELECT '+#13#10+
            '   CAST(''Hello'' AS varchar(max)) AS ColumnA, '+#13#10+
            '   CAST(''C6705EDE-CE58-4AB9-81BE-679AC1E75DE6'' AS uniqueidentifier) AS ColumnB,'+#13#10+
            '   CAST(''2466C151-88EC-40C0-B091-25B6BD74070C'' AS uniqueidentifier) AS ColumnC';


    rs := CoRecordset.Create;
    rs.Open(sql, connectionString, adOpenForwardOnly, adLockReadOnly, adCmdText);
    WriteLn('');

    WriteLn('Command text: ');
    WriteLn(sql);
    WriteLn;

    if rs.EOF then Exit; //just to shut people up

    WriteLn('Recordset Fields');
    for i := 0 to rs.Fields.Count-1 do
    begin
        fld := rs.Fields[i];
        if fld.DefinedSize = MaxInt then
            WriteLn(Format('   %d.  %s: %s(%s)', [i, fld.Name, DataTypeEnumToStr(fld.Type_), 'max']))
        else
            WriteLn(Format('   %d.  %s: %s(%d)', [i, fld.Name, DataTypeEnumToStr(fld.Type_), fld.DefinedSize]));
    end;
    WriteLn('');
    WriteLn('');

    WriteLn('Fields["ColumnA"]: "'+rs.Fields['ColumnA'].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields['ColumnA'].Value).VType)+')');
    WriteLn('Fields["ColumnC"]: "'+rs.Fields['ColumnC'].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields['ColumnC'].Value).VType)+')');
    WriteLn('Fields["ColumnB"]: "'+rs.Fields['ColumnB'].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields['ColumnB'].Value).VType)+')');
    WriteLn('');

    WriteLn('Fields[0]: "'+rs.Fields[0].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields[0].Value).VType)+')');
    WriteLn('Fields[2]: "'+rs.Fields[2].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields[2].Value).VType)+')');
    WriteLn('Fields[1]: "'+rs.Fields[1].Value+'"  (VType: '+IntToStr(TVarData(rs.Fields[1].Value).VType)+')');
    WriteLn('');



    DumpField('ColumnA');
    DumpField('ColumnB');
    s := DumpField('ColumnC');

    if s = '' then
    begin
        WriteLn(Format('WARNING: ColumnB expected to not-empty, but was "%s"',  [s]));
        Exit;
    end;
end;


begin
  try
        CoInitialize(nil);
        TestLoadingGUID;
  except
     on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
  end;

    WriteLn('Press enter to close');
    Readln;
end.

И консольный вывод

Enter name of server to connect to (leave blank for VADER):
ConnectionString: Provider=MSDASQL;Driver={SQL Server};Server={vader};Database=master;Trusted_Connection=Yes;


Command text:
SELECT
        CAST('Hello' AS varchar(max)) AS ColumnA,
        CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB,
        CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC

Recordset Fields
   0.  ColumnA: adLongVarChar(max)
   1.  ColumnB: adGUID(16)
   2.  ColumnC: adGUID(16)


Fields["ColumnA"]: "Hello"  (VType: 1)
Fields["ColumnC"]: "{2466C151-88EC-40C0-B091-25B6BD74070C}"  (VType: 8)
Fields["ColumnB"]: ""  (VType: 0)

Fields[0]: ""  (VType: 0)
Fields[2]: "{2466C151-88EC-40C0-B091-25B6BD74070C}"  (VType: 8)
Fields[1]: ""  (VType: 0)

Reading ColumnA column
   VType: 0
   Value: "" (as string)

Reading ColumnB column
   VType: 0
   Value: "" (as string)

Reading ColumnC column
   VType: 8
   Value: "{2466C151-88EC-40C0-B091-25B6BD74070C}" (as string)

WARNING: ColumnB expected to not-empty, but was ""
Press enter to close
Пример минимального кода (Javascript)

Чтобы расширить аудиторию, вот тот же код выше в javascript:

OdbcFails.js

main();

function main() {
  serverName = "vader";
  CRLF = "\r\n";

  var connectionString = "Provider=MSDASQL;Driver={SQL Server};Server={"+serverName+"};Database=master;Trusted_Connection=Yes;";
    WriteLn("ConnectionString: "+connectionString);
    WriteLn("");

  adOpenForwardOnly = 0;
  adLockReadOnly = 1;
  adCmdText = 1;
  var rs = new ActiveXObject("ADODB.Recordset");

  var sql = "SELECT "+CRLF+
            " CAST('Hello' AS varchar(max)) AS ColumnA, "+CRLF+
            " CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB,"+CRLF+
            " CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC";

    WriteLn("Command text:");
    WriteLn(sql);
    WriteLn("");

  WriteLn("Executing query");
  rs.open(sql, connectionString, adOpenForwardOnly, adLockReadOnly, adCmdText);
  WriteLn("Query complete");

    if (rs.EOF) return; //just to shut people up

  var columnC = rs("ColumnC").Value;
  var columnB = rs("ColumnB").Value;

   WriteLn("ColumnB: "+columnB);
   WriteLn("ColumnC: "+columnC);

}

function WriteLn(str) {
  WScript.Echo(str);
}  

И если вы запустите:

C:\Users\ian>cscript OdbcFails.js

Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

ConnectionString: Provider=MSDASQL;Driver={SQL Server};Server={vader};Database=master;Trusted_Connection=Yes;

Command text:
SELECT
 CAST('Hello' AS varchar(max)) AS ColumnA,
 CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB,
 CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC

Executing query
Query complete
ColumnB: undefined
ColumnC: {2466C151-88EC-40C0-B091-25B6BD74070C}
Пример минимального кода (html + javascript - только Internet Explorer)
<!doctype html>
<html>

<head>
    <script>
        function WriteLn(str) {
            console.log(str);
        }

        function main() {
            serverName = "vader";
            CRLF = "\r\n";

            var connectionString = "Provider=MSDASQL;Driver={SQL Server};Server={" + serverName + "};Database=master;Trusted_Connection=Yes;";
            WriteLn("ConnectionString: " + connectionString);
            WriteLn("");

            adOpenForwardOnly = 0;
            adLockReadOnly = 1;
            adCmdText = 1;
            var rs = new ActiveXObject("ADODB.Recordset");

            var sql = "SELECT " + CRLF +
                " CAST('Hello' AS varchar(max)) AS ColumnA, " + CRLF +
                " CAST('C6705EDE-CE58-4AB9-81BE-679AC1E75DE6' AS uniqueidentifier) AS ColumnB," + CRLF +
                " CAST('2466C151-88EC-40C0-B091-25B6BD74070C' AS uniqueidentifier) AS ColumnC";

            WriteLn("Command text:");
            WriteLn(sql);
            WriteLn("");

            WriteLn("Executing query");
            rs.open(sql, connectionString, adOpenForwardOnly, adLockReadOnly, adCmdText);
            WriteLn("Query complete");

            if (rs.EOF) return; //just to shut people up

            var columnC = rs("ColumnC").Value;
            var columnB = rs("ColumnB").Value;

            WriteLn("ColumnB: " + columnB);
            WriteLn("ColumnC: " + columnC);

        }

        main();

    </script>

    <body>
    </body>
    <script>
Бонус ЧтениеБлоги MSDN:Microsoft поддерживает ODBC для нативного реляционного доступа к данным (архив)Блог ADO.Net:Объявление об устаревании поставщика OLEDB для Microsoft SQL Server (архив)MSDN:Преобразование приложений SQL Server из OLE DB в ODBC (архив)HAL2020:OLE DB и SQL Server: история, финальная игра и некоторая «грязь» Microsoft (архив)Недопустимое чтение индекса дескриптора varchar (max) (архив)Форумы MSDN:Недопустимый индекс дескриптора, вызывающий SQLGetData (архив)IBM:Задание DataStage с ODBC Connector получает ошибку при использовании столбца больших объектов (архив)

Ответы на вопрос(0)

Ваш ответ на вопрос