Архитектурные ошибки OLEDB. Передача данных в виде COM-объектов.
При плотной работе с OLEDB интерфейсами, рано или поздно обнаруживаются мелкие «дыры». Которые создают неоправданную нагрузку на реализацию провайдера и потенциально могут приводить к утечкам ресурсов. К счастью, этих «дыр» очень мало. Одна из них — связана с передачей данных в виде прямого указателя на COM-объект (ICommand::Execute, IRowsetChange::SetData, IRowsetChange::Insert).
Проблема заключается в том, что в некоторых случаях за освобождение такого COM-объекта отвечает провайдер, а в некоторых — клиент. Все эти нюансы, к счастью, перечислены в документации. Однако зачем вообще было обязывать провайдер вызывать IUnknown::Release? Например, если вы передадите значение параметра в виде VARIANT (кстати, именно так всегда и поступает ADODB), то провайдер считывает из него данные, но ::VariantClear вызывать не должен. Даже если в варианте находится указатель на COM-объект.
Самое интересное, что эта чехарда с «освобождать/не освобождать» COM-объект идет в разрез с основным правилом COM: если вы передаете указатель на COM-объект, то получатель не принимает на себя всю ответственность за его время жизни. Конечно, он может вызывать для него пары AddRef/Release или QueryInterface/Release. Но вот так вот просто вызывать Release — вызываемая сторона не должна. Потому что это может уничтожить объект и приведет к проблемам у вызывающей стороны.
В итоге
- Сдается мне, что мега-мозг (которые проектировал интерфейсы OLEDB и формулировал правила поведения), в данном конкретном случае перемудрил.
- Если вам нужно передавать COM-объект в OLEDB провайдер, то лучше это делать через VARIANT (типы: VT_UNKNOWN, VT_DISPATCH).