MS Sql: определить типы полей рекодсета из программы
От: .alex Ниоткуда  
Дата: 14.09.22 16:58
Оценка:
Добрый день. Никак не получается корректно определить тип полей полученного рекодсета.
Например делаю таблицу:
use test

drop table if exists tbl
create table tbl
(
    fld_date date
    , fld_datetime datetime
    , fld_time time
    , fld_varchar varchar(50)
    , fld_int int
    , fld_float float
)
insert into tbl
select
'20220914'
, '20220914 15:12:33'
, '12:34:22'
, 'test string'
, 123
, 123.45


Потом пытаюсь определить тип каждого поля:
#include <iostream>
#include <string>
#include <msdasc.h>

#import "msado15.dll" no_namespace rename("EOF", "adoEOF")

std::string Type2Str(DataTypeEnum type)
{
    std::string sResult;
    switch (type)
    {
        case 0x2000: sResult = "AdArray"; break;
        case 20: sResult = "adBigInt"; break;
        case 128: sResult = "adBinary"; break;
        case 11: sResult = "adBoolean"; break;
        case 8: sResult = "adBSTR"; break;
        case 136: sResult = "adChapter"; break;
        case 129: sResult = "adChar"; break;
        case 6: sResult = "adCurrency"; break;
        case 7: sResult = "adDate"; break;
        case 133: sResult = "adDBDate"; break;
        case 134: sResult = "adDBTime"; break;
        case 135: sResult = "adDBTimeStamp"; break;
        case 14: sResult = "adDecimal"; break;
        case 5: sResult = "adDouble"; break;
        case 0: sResult = "adEmpty"; break;
        case 10: sResult = "adError"; break;
        case 64: sResult = "adFileTime"; break;
        case 72: sResult = "adGUID"; break;
        case 9: sResult = "adIDispatch"; break;
        case 3: sResult = "adInteger"; break;
        case 13: sResult = "adIUnknown"; break;
        case 205: sResult = "adLongVarBinary"; break;
        case 201: sResult = "adLongVarChar"; break;
        case 203: sResult = "adLongVarWChar"; break;
        case 131: sResult = "adNumeric"; break;
        case 138: sResult = "adPropVariant"; break;
        case 4: sResult = "adSingle"; break;
        case 2: sResult = "adSmallInt"; break;
        case 16: sResult = "adTinyInt"; break;
        case 21: sResult = "adUnsignedBigInt"; break;
        case 19: sResult = "adUnsignedInt"; break;
        case 18: sResult = "adUnsignedSmallInt"; break;
        case 17: sResult = "adUnsignedTinyInt"; break;
        case 132: sResult = "adUserDefined"; break;
        case 204: sResult = "adVarBinary"; break;
        case 200: sResult = "adVarChar"; break;
        case 12: sResult = "adVariant"; break;
        case 139: sResult = "adVarNumeric"; break;
        case 202: sResult = "adVarWChar"; break;
        case 130: sResult = "adWChar"; break;
        default: sResult = "err"; break;
    }
    return sResult;
}

void main()
{
    CoInitialize(NULL);

    _ConnectionPtr pConnection = NULL;
    _RecordsetPtr rs = NULL;
    try
    {
        pConnection.CreateInstance(__uuidof(Connection));
        pConnection->CommandTimeout = 0;
        std::string sConnectionString = "Provider=SQLOLEDB.1;Trusted_Connection=True;Initial Catalog=test;User ID=sa;Password=sa;Data Source=localhost";
        pConnection->Open(_bstr_t(sConnectionString.c_str()), _bstr_t(""), _bstr_t(""), adModeUnknown);
                
        HRESULT hr = rs.CreateInstance(__uuidof(Recordset));
        rs->CursorType = adOpenForwardOnly;
        rs->CursorLocation = adUseServer;
        rs->LockType = adLockReadOnly;
        rs->Open((_bstr_t)"select * from tbl", (IDispatch*)pConnection, adOpenForwardOnly, adLockReadOnly, adCmdText);

        _variant_t vtFldIdx;
        vtFldIdx.vt = VT_I2;
        for (vtFldIdx.iVal = 0; vtFldIdx.iVal < rs->Fields->GetCount(); vtFldIdx.iVal++)
        {
            std::cout << rs->Fields->GetItem(vtFldIdx)->Type << ": " << Type2Str(rs->Fields->GetItem(vtFldIdx)->Type) << std::endl;
        }


        rs->Close();
        pConnection->Close();
    }
    catch (_com_error& e)
    {
        std::cout << "COM err: " << (char*)e.Description() << std::endl;
        if (pConnection && (pConnection->State & adStateOpen) == adStateOpen) pConnection->Close();
        rs = NULL;
    }
    catch (...)
    {
        std::cout << "err" << std::endl;
        if (pConnection && (pConnection->State & adStateOpen) == adStateOpen) pConnection->Close();
        rs = NULL;
    }
}


Результат следующий:
202: adVarWChar
135: adDBTimeStamp
202: adVarWChar
200: adVarChar
3: adInteger
5: adDouble

т.е. тип date и time почему-то "не определились"... Что я деляю не правильно, подскажите пожалуйста...
Re: MS Sql: определить типы полей рекодсета из программы
От: BlackEric http://black-eric.lj.ru
Дата: 17.09.22 20:59
Оценка: +1
Здравствуйте, .alex, Вы писали:

Т.е. он определяет тип как adVarWChar. А какой версии у вас msado15.dll? Возможно поможет обновить библиотеку, хотя она вроде бы идет в поставке винды сейчас.
https://github.com/BlackEric001
Re[2]: MS Sql: определить типы полей рекодсета из программы
От: .alex Ниоткуда  
Дата: 06.10.22 13:19
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, .alex, Вы писали:


BE>Т.е. он определяет тип как adVarWChar. А какой версии у вас msado15.dll? Возможно поможет обновить библиотеку, хотя она вроде бы идет в поставке винды сейчас.


Взял прследнюю версию длл — 10.0.19041.746. поменял провайдер в строке подключения на:SQLNCLI11. Тип дат стал определятся нормально:

133: adDBDate
135: adDBTimeStamp
145: err
200: adVarChar
3: adInteger
5: adDouble

но теперь проблема с типом time(7), почему-то он определяется, как 145 что вообще не поименовано в enum DataTypeEnum, ну и при попытке преобразовать данные из колонки с типом time в строку:
std::string s = (const char*)_bstr_t(val);

вылетает исключение. Не подскажете, что можно сделать?
Re[3]: MS Sql: определить типы полей рекодсета из программы
От: qaz77  
Дата: 06.10.22 13:52
Оценка:
Здравствуйте, .alex, Вы писали:
A>Взял прследнюю версию длл — 10.0.19041.746. поменял провайдер в строке подключения на:SQLNCLI11. Тип дат стал определятся нормально:

В legacy режиме работы (про ADO не знаю, пишу про OBDC) нет типов для даты и времени по отдельности, есть только таймстемп.
А вот для Native Client такие отдельные типы есть.
В файл sqlncli.h есть константа SQL_SS_TIME2 — вот на нее почему-то мапится время, а не на SQL_TIME.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.