На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » И2Р Программы » Программирование » C, C++

Эффективное преобразование типов при работе с OLE DB

В статье речь пойдёт о применении стандартных средств OLEDB к задачам безопасных и эффективных преобразований типов. Важность задач этого типа является следствием широкого распространения подхода, при котором в ряде крупных коммерческих продуктов в качестве библиотеки для работы с СУБД используется OLE DB.

Краткое введение

Ряд крупных проектов современности (в том числе и тот, в котором работаю я) используеют в качестве библиотеки для работы с данными OLE DB. Будучи набором сравнительно низкоуровневых интерфейсов, OLE DB позволяет создавать на C++ высокоэффективный код для работы с данными. Об эффективности OLE DB говорит хотя бы то, что библиотека ADO, крайне распространённая среди пользователей VB, построена на базе OLE DB.

OLE DB является универсальным средством работы с данными и краеугольным камнем концепции UDA. По большому счёту, все объекты в OLE DB делятся на 2 группы: Потребители и Поставщики (consumers и providers, соответственно). Суть концепции "Поставщика" в представлении любого необходимого набора данных в виде совокупности строк упорядоченной некоторым образом информации. Очевидно, любую информацию можно представить в виде строк данных (хотя бы для этого и пришлось поместить её в малопонятный снаружи BLOB). Концепция "Потребителя" ещё проще: данные, предоставляемые "Поставщиком", используются для извлечения из них информации общепринятым образом: при помощи запросов или манипуляции с отдельным полями структур, которыми физически являются строки, предоставляемые "Поставщиком".

Microsoft предоставляет пользователям своих продуктов целый ряд "Поставщиков". С их списком можно ознакомиться в описании к MDAC - the Microsoft Data Access Components - которое можно найти в MSDN.

Кроме задач обеспечения возможности написания кода, который впоследствии будет использоваться в объектах-"поставщиках" или объектах-"потребителях", OLE DB предоставляет своим пользователям целый ряд средств, применение которых не связано непосредственно с "базами данных". Одним из таких средств является интерфейс IDataConvert.

Круг решаемых задач

Актуальность задач конвертирования данных очевидна: в том случае, когда из типа DATE необходимо получить его ts-эквивалент лучше знать, как это делается, вместо того, чтобы придумывать своё, возможно, оригинальное, но требующее дополнительного тестирования решение.

Вместо столь неэффективной траты времени предлагается использовать библиотеку преобразования типов OLE DB. Её существенно преимущество по сравнению с прочими решениями заключается в том, что предлагаемыми средствами можно пользоваться в любом проекте на C++, с какой бы другой (MFC и/или, ATL) библиотекой он ни работал. Для использования библиотеки преобразования типов необходимо и достаточно включить два заголовочных файла:

#include
#include

Используя msdadc.dll становится возможны решение следующих задач:

  1. Определение самой возможности преобразования одного типа данных в другой
  2. Преобразование Automation-incompatible данных всего лишь одним вызовом интерфейса IDataConvert

Иногда даже первая задача являет собой вызов программистскому мастерству, а сложности, связанные со второй могут превосходить все разумные пределы. В то же время IDataConvert позволяет выполнять следующие, не всегда тривиальные, преобразования:

Таблица 1. Некоторые преобразования
Исходный тип
Тип назначения
ERROR

ERROR, BSTR, WSTR, VARIANT

BSTR

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, BYTES, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, GUID, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT, PROPVARIANT

STR

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, BYTES, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, GUID, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT, PROPVARIANT

WSTR

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, BYTES, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, GUID, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT, PROPVARIANT

BYTES

I4, I8, UI4, UI8, BSTR, STR, WSTR, BYTES, GUID, VARIANT, PROPVARIANT

DATE

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, VARIANT, PROPVARIANT

DBDATE

BSTR, STR, WSTR, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, VARIANT

DBTIME

BSTR, STR, WSTR, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, VARIANT

DBTIMESTAMP

BSTR, STR, WSTR, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, VARIANT

FILETIME

I8, UI8, BSTR, STR, WSTR, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, VARIANT, PROPVARIANT

GUID

BSTR, STR, WSTR, BYTES, GUID, VARIANT, PROPVARIANT

NUMERIC

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT, PROPVARIANT

VARNUMERIC

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, BSTR, STR, WSTR, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT

Idispatch

I1, I2, I4, I8, UI1, UI2, UI4, UI8, R4, R8, BOOL, ERROR, BSTR, STR, WSTR, BYTES, DATE, DBDATE, DBTIME, DBTIMESTAMP, FILETIME, GUID, CY, DECIMAL, NUMERIC, VARNUMERIC, VARIANT, PROPVARIANT, IDispatch, IUnknown

IUnknown

VARIANT, IDispatch, IUnknown

IDataConvert

Интерфейс IDataConvert - сердце библиотеки преобразования типов. Он составлен тремя методами (здесь и далее по ссылке откроется новое окно с кодом примера).

Каждый из этих методов отвечает за свою часть работы по преобразованию данных:

  • CanConvert возвращает информацию, сообщающую о возможности или невозможности преобразовать один тип в другой
  • DataСonvert собственно преобразует данные из одно вида в другой
  • GetConversionSize - рассчитывает размер буфера для выходных данных таким образом, чтобы результат пеобразования мог уместиться в этом буфере.

Функционирование

Проиллюстрирую использование всех трёх функций на задаче, которую недавно пришлось решать: необходимо максимально эффективно решить проблему преобразования даты Windows в её строковое ts-представление. То есть, осуществить преобразование DATE -> DBTIMESTAMP -> CHAR.

Алгоритм выполнения этого задания:

  1. Проверить допустимость преобразования, используя CanConvert
  2. В случае допустимости выполнить преобразование, используя DataConvert
  3. Если прямое преобразование недопустимо, то использовать в качестве <посредника" тип DB_STR, как один из самых гибких, наряду с DB_VARIANT.

Хочу подчеркнуть важность первого шага этого алгоритма. В некоторых местах описание преобразований, предоставляемое MSDN, является неверным, поэтому, несмотря на данные в табл. 1, преобразования может не произойти. Проверка допустимости является обязательной.

Выполнить саму проверку просто. Если ds - переменная типа IDataConvert, то проверка возможности преобразования переменной типа DBTYPE_A в DBTYPE_B выглядит следующим образом:

HRESULT hr = ds->CanConvert(DBTYPE_A, DBTYPE_B)

Возвращаемый результат может принимать одно из трёх значений:

  • S_TRUE - прямое преобразование допустимо
  • S_FALSE - прямое преобразование недопустимо
  • E_INVALIDARG - один или оба аргумента содержат неверный описатель типа. То есть такой, который не определён в перечислении DBTYPE

Преобразование из DBTYPE_A в DBTYPE_B выполняется так:

hr = dc->DataConvert(DBTYPE_A, DBTYPE_B, sizeof(src_buff), &dest_size, (PVOID)&src_buff, (PVOID)&dest_buff, MAX_SIZE_OF_DEST_BUFFER, DBSTATUS_S_OK, &afterop, 0, 0, DBDATACONVERT_DEFAULT);

Листинг 1. Шаблон вызова метода преобразования параметров

Так, например, преобразование из типа DBTYPE_DATE в тип DBTYPE_STR выполняется следующим фрагментом кода:

char * buffer = new char[BIG_ENOUGH]; DBSTATUS after_operation = -1; DATE date; ULONG size_needed;

hr = dc->DataConvert(DBTYPE_DATE, DBTYPE_STR, sizeof(DATE), &size_needed, (PVOID)&date, (PVOID)buffer, BIG_ENOUGH, DB_STATUS_OK, &after_operation, 0, 0, DBDATACONVERT_DEFAULT);

Листинг 2. Преобразование из типа DATE в тип char

Последний параметр, имеющий тип DBDATACONVERT может принимать одно из трёх значений:

Значение
Смысл
DBDATACONVERT_DEFAULT

Не оговаривается никаких особых условий преобразования

DBDATACONVERT_SETDATABEHAVIOR

Этот флаг указывает на то, что усечение данных является ошибкой и что область памяти, на которую указывает в листинге 2 buffer не будет изменяться в случае таких ошибок

DBDATACONVERT_LENGTHFROMNTS

Этот флаг указывает на то, что если тип данных, ИЗ которого производится преобразование принадлежит множеству (DBTYPE_STR, DBTYPE_WSTR), то длина третьего параметра (в случае листинга 2 жёстко записанная, как size_of(DATE)) будет вычисляться библиотекой из переменной, являющейся указателем на источник данных

Четвёртый параметр, pcbDstLength, при удачном вызове метода будет содержать размер буфера, в который будут помещены результаты преобразования. Это может быть полезно в случае использования типов данных переменной длины.

Шестой параметр, pDst, или в листинге 2, (PVOID)buffer, не так одназначен, как можно подумать, глядя на его сигнатуру. Дело в том, что наряду с одним уровнем косвенности - PVOID - он может работать и с (PVOID*). Более подробная информация об использовании буфера в такой роли может быть получена здесь: mk:@MSITStore:C:\MSDN-I~1\MSDN\oledb.chm::/htm/oledbtype_indicators.htm.

Девятый параметр, pdbsStatus, или в листинге 2, &after_operation содержит информацию о состоянии объекта преобразования после выполнения операции и, являясь стандартным индикатором OLE DB, принимает одно из значений перечисления DBSTATUSENUM. Дополнительная польза от этого параметра может быть получена в том случае, когда требуется получить расширенную информацию о произошедшей во время преобразования ошибке.

Заключительное замечание: при компиляции кода, написанного в соответствии с последними спецификациями Microsoft, можно столкнуться с тем, что в некоторых случаях код не будет компилироваться, выдавая нечто вроде: "undefined symbol DBLENGTH", когда вы будете пользоваться этим типом. Причина проста: в настоящее время существуют по меньшей мере две различные версии заголовочных файлов OLE DB. Одна из этих версий входит в состав Visual C++, а другая, более новая, в состав Platform SDK. Если проект, в котором вы сейчас работаете, позволяет это, я рекомендую использовать ту версию заголовочных файлов, которая входит в состав SDK.

Юрий Кулешов
Софтерра

Другие разделы
C, C++
Java
PHP
VBasic, VBS
Delphi и Pascal
Новое в разделе
Базы данных
Общие вопросы
Теория программирования и алгоритмы
JavaScript и DHTML
Perl
Python
Active Server Pages
Программирование под Windows
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100