SQLRU.net
Разработка приложений баз данных

Начало » Программирование » C++ » MS Sql: определить типы полей рекодсета из программы
MS Sql: определить типы полей рекодсета из программы [сообщение #4230] Wed, 24 January 2024 19:14 Переход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
Добрый день. Никак не получается корректно определить тип полей полученного рекодсета.
Например делаю таблицу:
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 почему-то "не определились"...

поменял провайдер в строке подключения на: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: MS Sql: определить типы полей рекодсета из программы [сообщение #4238 является ответом на сообщение #4230] Thu, 25 January 2024 10:50 Переход к предыдущему сообщениюПереход к следующему сообщению
BlackEric в настоящее время не в онлайне  BlackEric
Сообщений: 367
Зарегистрирован: June 2022
Senior Member
вот один в один обсуждение было...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4241 является ответом на сообщение #4238] Thu, 25 January 2024 11:34 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
Так я и задавал, но ответа не получил... Думал может тут...
Может на стэковерфлоу спросить...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4243 является ответом на сообщение #4241] Thu, 25 January 2024 14:42 Переход к предыдущему сообщениюПереход к следующему сообщению
BlackEric в настоящее время не в онлайне  BlackEric
Сообщений: 367
Зарегистрирован: June 2022
Senior Member
Так за полтора года решение и не нашли?

Спросите...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4246 является ответом на сообщение #4230] Thu, 25 January 2024 16:09 Переход к предыдущему сообщениюПереход к следующему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
badhabit писал(а) Wed, 24 January 2024 17:14

но теперь проблема с типом time(7), почему-то он определяется, как 145 что вообще не поименовано в enum DataTypeEnum, ну и при попытке преобразовать данные из колонки с типом time в строку:
std::string s = (const char*)_bstr_t(val);
вылетает исключение. Не подскажете, что можно сделать?
Подключать специфичный заголовок: https://learn.microsoft.com/en-us/sql/relational-databases/n ative-client-ole-db-date-time/data-type-support-for-ole-db-d ate-and-time-improvements?view=sql-server-ver15

И не пытаться интерпретировать неизвестный тип как указатель на nul-terminated строку (из-за чего и "вылетает исключение").

[Обновления: Thu, 25 January 2024 16:11]

Известить модератора

Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4258 является ответом на сообщение #4243] Fri, 26 January 2024 14:21 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
BlackEric писал(а) Thu, 25 January 2024 14:42
Так за полтора года решение и не нашли?
Спросите...
Нет, тогда задача отложилась, теперь опять актуальна..
Цитата:
Подключать специфичный заголовок: https://learn.microsoft.com/en-us/sql/relational-databases/n ative-client-ole-db-date-time/data-type-support-for-ole-db-d ate-and-time-improvements?view=sql-server-ver15
И не пытаться интерпретировать неизвестный тип как указатель на nul-terminated строку (из-за чего и "вылетает исключение").
О, спасибо! Только я что-то опять же не соображу как... Подключил #include <c:\Program Files\Microsoft SQL Server\110\SDK\Include\sqlncli.h> -  исключение перестало вылетать, но как получить данные? Опять же приходит в голову только преобразование в строку... std::string s = (const char*)_bstr_t(vtFldIdx);
			if (rs->Fields->GetItem(vtFldIdx)->Type == DBTYPE_DBTIME2)
			{
				std::string s = (const char*)_bstr_t(vtFldIdx);
				std::cout << s << std::endl;
			}
но выводится почемуто просто цифра: 2  :roll:
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4260 является ответом на сообщение #4258] Fri, 26 January 2024 16:11 Переход к предыдущему сообщениюПереход к следующему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
Ну там же чёрным по белому описана структура DBTIME2...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4263 является ответом на сообщение #4260] Fri, 26 January 2024 16:32 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
SD писал(а) Fri, 26 January 2024 16:11
Ну там же чёрным по белому описана структура DBTIME2...
Да, структуру видел. Но не понятно, как variant_t преобразовать в DBTIME2? Подскажите пожалуйста...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4264 является ответом на сообщение #4263] Sat, 27 January 2024 01:50 Переход к предыдущему сообщениюПереход к следующему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
https://learn.microsoft.com/en-us/sql/relational-databases/n ative-client-ole-db-data-types/ssvariant-structure
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4301 является ответом на сообщение #4264] Wed, 31 January 2024 13:07 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
SD писал(а) Sat, 27 January 2024 01:50
https://learn.microsoft.com/en-us/sql/relational-databases/n ative-client-ole-db-data-types/ssvariant-structure
Что-то я видимо ничего не понимаю... и в инете примеров совсем не нашел, ссылка только на эту статью хелпа... Не понимаю я, что надо в memcpy писать... Есть у меня значение ячейки в переменной _variant_t val; помогите её в DBTIME2 переделать...
#include <iostream>
#include <string>

#include <iostream>
#include <string>
#include <c:\Program Files\Microsoft SQL Server\110\SDK\Include\sqlncli.h>

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

void main()
{
	CoInitialize(NULL);
	SetConsoleOutputCP(1251);
	SetConsoleCP(1251);

	_ConnectionPtr pConnection = NULL;
	_RecordsetPtr rs = NULL;
	try
	{
		pConnection.CreateInstance(__uuidof(Connection));
		pConnection->CommandTimeout = 0;
		std::string sConnectionString = "Provider=SQLNCLI11;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;
			
			_variant_t val = rs->Collect[vtFldIdx];
			if (val.vt != VT_NULL)
			{
				if (rs->Fields->GetItem(vtFldIdx)->Type == DBTYPE_DBTIME2)
				{
					SSVARIANT ssDst = {0};
					SSVARIANT* pssDst = &ssDst;
					memcpy(&V_SS_TIME2(pssDst).tTime2Val, val, sizeof(DBTIME2)/*cbNative*/);
				}
				else
				{
					std::cout << (const char*)_bstr_t(val) << 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;
	}
}
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4304 является ответом на сообщение #4301] Wed, 31 January 2024 16:02 Переход к предыдущему сообщениюПереход к следующему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
Для начала получи непосредственно подлежащий VARIANT через Value и проверь у него значение поля vt. При некотором везении дальше достаточно простого reinterpret_cast в SSVARIANT.
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4310 является ответом на сообщение #4304] Wed, 31 January 2024 19:24 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
SD писал(а) Wed, 31 January 2024 16:02
Для начала получи непосредственно подлежащий VARIANT через Value и проверь у него значение поля vt. При некотором везении дальше достаточно простого reinterpret_cast в SSVARIANT.
Пытаюсь...
			_variant_t val = rs->Fields->GetItem(vtFldIdx)->Value;
			if (val.vt != VT_NULL)
			{
				if (rs->Fields->GetItem(vtFldIdx)->Type == DBTYPE_DBTIME2)
				{
					SSVARIANT *pssDst = reinterpret_cast<SSVARIANT*>(val);
				}
			}

Говорит:
Цитата:
Error C2440 'reinterpret_cast': cannot convert from '_variant_t' to 'SSVARIANT'
что я делаю не так?
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4316 является ответом на сообщение #4310] Thu, 01 February 2024 01:36 Переход к предыдущему сообщениюПереход к следующему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
Не пропускай буквы при чтении. Повторяю: получи непосредственно подлежащий VARIANT.
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4340 является ответом на сообщение #4316] Fri, 02 February 2024 13:58 Переход к предыдущему сообщениюПереход к следующему сообщению
badhabit в настоящее время не в онлайне  badhabit
Сообщений: 7
Зарегистрирован: January 2024
Junior Member
SD писал(а) Thu, 01 February 2024 01:36
Не пропускай буквы при чтении. Повторяю: получи непосредственно подлежащий VARIANT.
А как это сделать? Я не знаю...
Re: MS Sql: определить типы полей рекодсета из программы [сообщение #4341 является ответом на сообщение #4340] Fri, 02 February 2024 16:04 Переход к предыдущему сообщению
SD в настоящее время не в онлайне  SD
Сообщений: 414
Зарегистрирован: August 2022
Senior Member
Я тоже не знаю. Изучай исходники _variant_t.
Предыдущая тема: Проект CMake (MSVS 2022), задать precompiled header
Следующая тема: собрать fbclient.lib под bcc64 (embarcadero clang)
Переход к форуму:
  


Текущее время: Mon Dec 09 22:44:52 GMT+3 2024

Общее время, затраченное на создание страницы: 0.00793 секунд